diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9ebe0555b9b6f4745c25e3e1bf09a3c1723a05eb..86e0471c2e03a88aa822e20854891a9e8fb1be2c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -11,7 +11,7 @@ variables:
   LSAN_OPTIONS: "log_threads=1"
   ASAN_OPTIONS: "detect_leaks=0:detect_stack_use_after_return=1"
   # location of AirShowerPhysics/corsika-data
-  CORSIKA_DATA: "${CI_PROJECT_DIR}/Data" # the git submodule
+  CORSIKA_DATA: "${CI_PROJECT_DIR}/modules/data" # the git submodule
   # _alternatively_ corsika-data can be downloaded as submodule:
   GIT_SUBMODULE_STRATEGY: normal # none: we get the submodules in before_script,
                                  # normal: get submodules automatically
@@ -29,7 +29,6 @@ stages:
   - build
   - test
   - build_test
-  - python
   - example
   - build_test_example
   - install
@@ -272,8 +271,6 @@ build_test-clang-8:
 # normal pipeline for each commit
 .example:
   stage: example
-  before_script:
-    - apt-get -qq update && apt-get -qq install -y gdb
   tags:
     - corsika
   script:
@@ -328,8 +325,6 @@ example-clang-8:
   stage: build_test_example
   tags:
     - corsika
-  before_script:
-    - apt-get -qq update && apt-get -qq install -y gdb
   script:
     - cd build
     - cmake --build . -- -j4
@@ -438,8 +433,6 @@ install-clang-8:
   stage: optional
   tags:
     - corsika
-  before_script:
-    - apt-get -qq update && apt-get -qq install -y gdb
   script:
     - cd build
     - cmake .. -DCMAKE_BUILD_TYPE=Release
@@ -604,36 +597,3 @@ sanity:
     key: "${CI_COMMIT_REF_SLUG}-gcc"
 
 
-
-##########################################################
-# template for all Python jobs
-.python:
-  stage: python
-  tags:
-    - corsika
-  script:
-    - cd ${CI_PROJECT_DIR}/Python  # change into the Python directory
-    - pip install --user -e '.[test]'  # install the package + test deps
-    - make all 2&>1 | tee python-test.log  # this runs all of the Python tests
-    - echo "finished" >> python-test.log # create even an empty file...
-    - cd ${CI_PROJECT_DIR}  # reset the directory    
-  artifacts:
-    when: always
-    expire_in: 1 year
-    paths:
-      - ${CI_PROJECT_DIR}/Python/python-test.log
-  allow_failure: true
-
-# we now configure the jobs for the three
-# supported Python versions
-python-3.6:
-  extends: .python
-  image: python:3.6
-
-python-3.7:
-  extends: .python
-  image: python:3.7
-
-python-3.8:
-  extends: .python
-  image: python:3.8
diff --git a/.gitmodules b/.gitmodules
index 185d42cffbd8fdb9c3afd31f6f8434ed02fab762..0a6018dcbebc5d0b8f89ad6d554a3ad69e614168 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,12 +1,19 @@
-[submodule "Data"]
-	path = Data
+[submodule "modules/data"]
+	path = modules/data
 	url = ../../AirShowerPhysics/corsika-data
 	branch = master
-[submodule "ThirdParty/spdlog"]
-	path = ThirdParty/spdlog
+        shallow = true
+[submodule "externals/spdlog"]
+	path = externals/spdlog
 	url = https://github.com/gabime/spdlog.git
-	shallow = true
-[submodule "Processes/Proposal/PROPOSAL"]
-	path = Processes/Proposal/PROPOSAL
+        shallow = true
+[submodule "modules/proposal"]
+	path = modules/proposal
 	url = https://github.com/tudo-astroparticlephysics/PROPOSAL.git
-	shallow = true
+	branch = restructure_parametrization
+        shallow = true
+[submodule "modules/conex"]
+	path = modules/conex
+	url = ../../AirShowerPhysics/cxroot
+	branch = master
+        shallow = true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dcaeb1ad4dd92321727b82a2fa8e45771930f0be..82eed84eee96ed44175f5c6701acee3c20f2f1f5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,135 +1,238 @@
 cmake_minimum_required (VERSION 3.9)
-# we would need 3.16 to have CMP0097 for external subproject submodule (non) support
-
+#
+#+++++++++++++++++++++++++++++
+# prevent in-source builds and give warning message
+#
+if ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") 
+  message (FATAL_ERROR "In-source builds are disabled.
+    Please create a build-dir and use `cmake <source-dir>` inside it.
+    NOTE: cmake will now create CMakeCache.txt and CMakeFiles/*.
+          You must delete them, or cmake will refuse to work.")
+endif ()
+#
 #+++++++++++++++++++++++++++++
 # project name
 #
-project( CORSIKA8_Modules_Tests_Examples )
+project (
+  corsika
+  VERSION 8.0.0
+  DESCRIPTION "CORSIKA C++ project (alpha status)"
+  LANGUAGES CXX
+  )
 #
+#+++++++++++++++++++++++++++++
+# as long as there still are modules using it:
+#
+enable_language (Fortran)
+set (CMAKE_Fortran_FLAGS "-std=legacy -Wfunction-elimination")
 #
 #+++++++++++++++++++++++++++++
 # warn user if system is not UNIX
 #
-if(NOT UNIX)
-  message(FATAL_ERROR "| CORSIKA8 > This is an unsupported system.")
-endif()
+if (NOT UNIX)
+  message (FATAL_ERROR "| CORSIKA8 > This is an unsupported system.")
+endif ()
 #
 #+++++++++++++++++++++++++++++
-# cmake path dir
+# cmake path dir, and cmake config
 #
-SET(CORSIKA8_CMAKE_DIR "${PROJECT_SOURCE_DIR}/cmake")
-SET(CMAKE_MODULE_PATH  "${CORSIKA8_CMAKE_DIR}" ${CMAKE_MODULE_PATH})
-SET(CMAKE_VERBOSE_MAKEFILE  ON)
+set (CORSIKA8_CMAKE_DIR "${PROJECT_SOURCE_DIR}/cmake")
+set (CMAKE_MODULE_PATH  "${CORSIKA8_CMAKE_DIR}" ${CMAKE_MODULE_PATH})
+include (CorsikaUtilities) # extra cmake function
+set (CMAKE_VERBOSE_MAKEFILE  OFF) # this can be done with `make VERBOSE=1`
+# ignore many irrelevant Up-to-date messages during install
+set (CMAKE_INSTALL_MESSAGE LAZY)
 #
 #+++++++++++++++++++++++++++++
 # check if compiler is C++17 compliant
 #
-include(CheckCXXCompilerFlag)
-CHECK_CXX_COMPILER_FLAG("--std=c++17" COMPILER_SUPPORTS_CXX17)
-if(NOT COMPILER_SUPPORTS_CXX17)
- message(FATAL "| CORSIKA8 > The compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Please use a different C++ compiler.")
-endif()
-
+include (CheckCXXCompilerFlag)
+check_CXX_compiler_flag ("--std=c++17" COMPILER_SUPPORTS_CXX17)
+if (NOT COMPILER_SUPPORTS_CXX17)
+ message (FATAL "| CORSIKA8 > The compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Please use a different C++ compiler.")
+endif ()
 # set CXX compile flags and options and warning settings
 set (CMAKE_CXX_STANDARD 17)
 set (CMAKE_CXX_EXTENSIONS OFF)
-
+#
+#+++++++++++++++++++++++++++++
+# Compiler and linker flags, settings
+#
 # enable warnings and disallow non-standard language
 # configure the various build types here, too
 # FYI: optimizer flags: -O2 would not trade speed for size, neither O2/3 use fast-math
 # debug: O0, relwithdebinfo: 02, release: O3, minsizerel: Os (all defaults)
 set (CMAKE_CXX_FLAGS "-Wall -pedantic -Wextra -Wno-ignored-qualifiers")
 set (CMAKE_Fortran_FLAGS "-std=legacy -Wfunction-elimination")
-
+set (DEFAULT_BUILD_TYPE "Release")
+#
 # clang produces a lot of unecessary warnings without this:
-add_compile_options ("$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wno-nonportable-include-path>")
+add_compile_options (
+  $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wno-nonportable-include-path>
+  )
+#
+#+++++++++++++++++++++++++++++
+# Build types settings
+#
+# setup coverage build type
+set (CMAKE_CXX_FLAGS_COVERAGE "-g --coverage")
+set (CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage")
+set (CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage")
+# set a flag to inform code that we are in debug mode
+set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
+#
+#+++++++++++++++++++++++++++++
+# Build type selection
+#
+# Set the possible values of build type for cmake-gui and command line check
+set (ALLOWED_BUILD_TYPES Debug Release MinSizeRel RelWithDebInfo Coverage)
+set_property (CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${ALLOWED_BUILD_TYPES})
+# Set a default build type if none was specified
+# by default: "Debug", if local ".git" directory is found, otherwise "Release"
+set (DEFAULT_BUILD_TYPE "Release")
+if (EXISTS "${CMAKE_SOURCE_DIR}/.git")
+  set (DEFAULT_BUILD_TYPE "Debug")
+endif ()
+if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  message (STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as no other was specified.")
+  set (CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE
+      STRING "Choose the type of build." FORCE)
+else (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  # Ignore capitalization when build type is selected manually and check for valid setting
+  string (TOLOWER ${CMAKE_BUILD_TYPE} SELECTED_LOWER)
+  string (TOLOWER "${ALLOWED_BUILD_TYPES}" BUILD_TYPES_LOWER)
+  if (NOT SELECTED_LOWER IN_LIST BUILD_TYPES_LOWER)
+    message (FATAL_ERROR "Unknown build type: ${CMAKE_BUILD_TYPE} [allowed: ${ALLOWED_BUILD_TYPES}]")
+  endif ()
+  message (STATUS "Build type is: ${CMAKE_BUILD_TYPE}")
+endif (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+#
+#+++++++++++++++++++++++++++++
+# Coverage
+#
+# targets and settings needed to generate coverage reports
+if (CMAKE_BUILD_TYPE STREQUAL Coverage)
+  find_package (Perl REQUIRED)
 
-# ctest config
+  # compile coverage under -O0 to avoid any optimization, function elimation etc.
+  add_compile_options ("-O0")
+  
+  set (GCOV gcov CACHE STRING "gcov executable" FORCE)
+  set (LCOV_BIN_DIR "${PROJECT_SOURCE_DIR}/externals/lcov/bin")
+  # collect coverage data
+  add_custom_command (
+    OUTPUT raw-coverage.info
+    COMMAND ${CMAKE_COMMAND} -E echo "Note: you need to run ctest at least once to generate the coverage data"
+    COMMAND ${LCOV_BIN_DIR}/lcov --gcov-tool=${GCOV} --directory . --capture --output-file raw-coverage.info
+    )
+  # remove uninteresting entries
+  add_custom_command (
+    OUTPUT coverage.info
+    COMMAND ${LCOV_BIN_DIR}/lcov -q --remove raw-coverage.info "*/usr/*" "/usr/*" --output-file coverage2.info
+    COMMAND ${LCOV_BIN_DIR}/lcov --remove coverage2.info "*/externals/*" "*/tests/*" "*/sibyll2.3d.cpp" "*/include/Pythia8/*" "${CMAKE_CURRENT_SOURCE_DIR}/modules/*" "${CMAKE_CURRENT_BINARY_DIR}/modules/*" --output-file coverage.info
+    COMMAND ${CMAKE_COMMAND} -E remove coverage2.info
+    DEPENDS raw-coverage.info
+    )
+  # generate html report
+  add_custom_command (
+    OUTPUT coverage-report
+    COMMAND ${LCOV_BIN_DIR}/genhtml --demangle-cpp coverage.info -o coverage-report
+    DEPENDS coverage.info
+    )
+  add_custom_target (coverage DEPENDS coverage-report)
+endif ()
+#
+#+++++++++++++++++++++++++++++
+# CTest config
+#
 enable_testing ()
-set (CTEST_OUTPUT_ON_FAILURE 1)
-
-
+if (${CMAKE_VERSION} VERSION_LESS "3.12.0")  
+  list (APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure")
+else (${CMAKE_VERSION} VERSION_LESS "3.12.0")
+  set (CTEST_OUTPUT_ON_FAILURE 1) # this is for new versions of cmake
+endif (${CMAKE_VERSION} VERSION_LESS "3.12.0")
+set (CTEST_CUSTOM_COVERAGE_EXCLUDE "./tests/" "./examples/" "./modules/" "test*.(hpp/cpp)$")
+# include this test only if NOT run on gitlab-ci; On CI this is a dedicated job:
+if (NOT DEFINED ENV{CI})
+  # add call to ./do-copyright.py to run as unit-test-case
+  add_test (NAME copyright_notices COMMAND ./do-copyright.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+endif (NOT DEFINED ENV{CI})
+#
 #+++++++++++++++++++++++++++++
-# get CORSIKA8
+# Options
 #
-find_package(CORSIKA8 REQUIRED)
-include_directories(${CORSIKA8_INCLUDE_DIR})
-# those are needed, since some headers (namely GeneratedParticleProperties.inc) are produced by python script from ParticleData.xml
-add_subdirectory(corsika/framework) 
-add_subdirectory(corsika/modules/sibyll) 
-add_subdirectory(corsika/modules/qgsjetII) 
+# HISTORY option selection
+option (WITH_HISTORY "Flag to switch on/off HISTORY" ON)
+#
+#+++++++++++++++++++++++++++++
+# Externals
+#
+set (Python_ADDITIONAL_VERSIONS 3)
+find_package (PythonInterp 3 REQUIRED)
 #
 #+++++++++++++++++++++++++++++
 # get Eigen3 
 #
-find_package( Eigen3 REQUIRED )
-include_directories(${EIGEN3_INCLUDE_DIR})
-
+find_package (Eigen3 3.3.4  REQUIRED)
+#
 #+++++++++++++++++++++++++++++
 # get catch2 
 #
-find_package( Catch2 REQUIRED )
-
+find_package (Catch2 2.13.2 REQUIRED)
+#
 #+++++++++++++++++++++++++++++
 # use spdlog
 #
-add_subdirectory(externals/spdlog)
-add_dependencies(CORSIKA8 spdlog::spdlog)
-
-#+++++++++++++++++++++++++++++
-# get phys_units
+add_subdirectory (externals/spdlog)
 #
-find_package( PhysUnits REQUIRED )
-
 #+++++++++++++++++++++++++++++
-# get Pythia
+# use zlib
 #
-#find_package( Pythia8 REQUIRED )
-add_subdirectory(dependencies/pythia)
-if(Pythia_FOUND)
-include_directories(${Pythia_INCLUDE_DIR})
-endif(Pythia_FOUND)
+find_package (ZLIB REQUIRED)
 #
 #+++++++++++++++++++++++++++++
-# get UrQMD
-#
-#find_package( UrQMD REQUIRED )
-add_subdirectory(dependencies/urqmd)
-if(UrQMD_FOUND)
-include_directories(${UrQMD_INCLUDE_DIR})
-endif(UrQMD_FOUND)
+# get phys_units
 #
-#+++++++++++++++++++++++++++++
-# get Sybill
+find_package (PhysUnits REQUIRED)
 #
-# find_package( Sibyll REQUIRED )
-add_subdirectory (dependencies/sibyll)
-if(Sibyll_FOUND)
-include_directories(${Sibyll_INCLUDE_DIR})
-endif(Sibyll_FOUND)
 #
 #+++++++++++++++++++++++++++++
-# get QGSJETII
+# CORSIKA8
 #
-#find_package( QGSJETII REQUIRED )
-add_subdirectory (dependencies/qgsjetII)
-if(QGSJETII_FOUND)
-include_directories(${QGSJETII_INCLUDE_DIR})
-endif(QGSJETII_FOUND)
+add_library (CORSIKA8 INTERFACE)
+target_include_directories (
+  CORSIKA8
+  INTERFACE
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}>
+  )
+target_link_libraries (
+  CORSIKA8
+  INTERFACE
+  PhysUnits
+  Eigen3::Eigen
+  spdlog::spdlog
+  )
+# those are needed, since some headers (namely GeneratedParticleProperties.inc) are produced by python script from ParticleData.xml
+add_subdirectory (src)
 #
 #
 #+++++++++++++++++++++++++++++
 # =~~~~~~~~~~~~~~~~~~~~~~~~~=
 #  = Add of subdirectories =
 # =~~~~~~~~~~~~~~~~~~~~~~~~~=
-#+++++++++++++++++++++++++++++
 #
+#+++++++++++++++++++++++++++++
 # modules
-# 
-#add_subdirectory (dependencies/Pythia)
-#add_subdirectory (dependencies/Sibyll)
-#add_subdirectory (dependencies/QGSJetII)
-#add_subdirectory (dependencies/UrQMD)
+#
+set (NO_BOOST 1) # do not use libboost_iostream in CorsikaData
+add_subdirectory (modules/data)
+add_subdirectory (modules/pythia)
+add_subdirectory (modules/sibyll)
+add_subdirectory (modules/qgsjetII)
+add_subdirectory (modules/urqmd)
+add_subdirectory (modules/conex)
 #
 #+++++++++++++++++++++++++++++++
 # tests
@@ -147,4 +250,7 @@ add_subdirectory (examples)
 #+++++++++++++++++++++++++++++++
 #
 # final summary output
+#
+include (FeatureSummary)
+add_feature_info (HISTORY WITH_HISTORY "Full information on cascade history for particles.")
 feature_summary (WHAT ALL)
diff --git a/COLLABORATION_AGREEMENT.md b/COLLABORATION_AGREEMENT.md
index bdc9bdf9e5aa3406e6eb6208ad31d481ba3c7c6b..ea9ed3634e0dd71c403ef0025ff6ad86bff94821 100644
--- a/COLLABORATION_AGREEMENT.md
+++ b/COLLABORATION_AGREEMENT.md
@@ -23,12 +23,13 @@ liability and licensing question are only handled by the adopted
 software license.
 
 ## The software license of the CORSIKA project
+
 The license adopted for the CORSIKA project is the explicit copyleft
 license GPLv3, as copied in full in the file
 [LICENSE](LICENSE). Each source file of the CORSIKA project contains a
 short statement of the copyright and this license. Each binary or
 source code release of CORSIKA contains the file LICENSE. The
-code, documentation and content in the folder [ThirdParty](ThirdParty)
+code, documentation and content in the folder [externals](externals)
 is not integral part of the CORSIKA project and can be based on, or
 include, other licenses, which must be compatible with GPLv3. Check the
 content of this folder for details and additional license information. It depends on the configuration of
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e2e3262aa0aaf5133d5f1758c190f85aac1fe559..be0fb7e43a6f4def6aed87491b0a862f4b0ba483 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@ change/improve them.
 
 # How to contribute
 
-  - We organize all development via `Issues` that may be feature requests,
+  - We organize all development via gitlab `Issues` that may be feature requests,
     ideas, discussions, or bugs fix requests. 
   - New issues can be created, or existing issues
     picked up or contributed to. 
@@ -19,7 +19,7 @@ change/improve them.
     created directly via the gitlab web interface. 
   - Proposed code to close one issue (located in a specific git
     branch) is reviewed, discussed, and eventually merged
-    into the master branch to close the issue.
+    into the master branch via a merge-request (MR) to close the issue.
   - all merge request will undergo a code review, and must be approved before merge, in order to ensure high code qualtiy: [Code Approval Procedure](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/-/wikis/Code-Approval-Procedure)
 
 
@@ -32,9 +32,9 @@ formatting. We provide a script `do-clang-format.sh`, which can be
 very useful. But we urge everybody to integrate `clang-format` already
 on the level of your source code editor. See [the official
 page](https://clang.llvm.org/docs/ClangFormat.html) for information
-about `clang-format` and its editor integration. At least: run
-`do-clang-format.sh` prior to any `git add` command. Code with
-improper formatting will not be accepted for merging. 
+about `clang-format` and its editor integrations. At least: run
+`do-clang-format.sh` prior to any `git add/commit` command. Code with
+improper formatting will not be accepted for merging. It will trigger automatic warnings by the continuous integration (CI) system.
 
 The definition of source code format is written down in the file
 [.clang-format](.clang-format) and can be changed, if the CORSIKA
@@ -43,138 +43,36 @@ e.g. [link1](https://clangformat.com/) or
 [link2](https://zed0.co.uk/clang-format-configurator/).
 
 
-## Naming conventions
-
-While `clang-format` does the structural formatting, we still need to agree on naming conventions:
-
-  - Classes and structs start with capital letters ```LikeThis```
-  - Class member variables start non-captial and have a trailing "_" ```likeThis_```
-  - Class member functions start with small letters ```LikeThis::doSomething(...)``` or ```LikeThis::do_something(...)```
-  - Any class setter begins with "set_" ```LikeThis::set_something(...)```
-  - Any class getter is named accoring to its property: ```LikeThis::something()```
-  - Logical getters may start with ```is_``` or ```has_```
-  - enums should be ```enum class``` 
-  - Named variables start with small letter ```likeThis```
-  - types in template definitions start with "T" ```TLikeThis```
-  
-  - use names that explain and document the code, thus for example
-  ``` 
-     TimeType TimeOfIntersection(Line const& line, Plane const& plane) {
-         auto const line_direction = line.GetDirection();     
-         auto const plane_normal = plane.GetNormal();     
-         return plane_normal.dot(plane.GetCenter()-line.GetPosition()) / plane_normal.dot(line_direction);     
-         }
-  ```
-    and not 
-  ```
-       TimeType TimeOfIntersection(Line const& l, Plane const& p) {
-         auto const d = p.GetCenter() - l.GetR0();     
-         auto const v = l.GetV0();     
-         auto const n = p.GetNormal();     
-         auto const c = n.dot(v);    
-         return n.dot(d) / c;     
-         }
-  ```
-    This actually is suffient to document the code, no further comments should be added in such cases. Only if further clarification is needed.  
-
-  - We use namespaces to avoid clashes and to structure code
-    - *Everything* is part of one of those namespaces:
-       - ```corsika::framework```, ```corsika::physics```, or ```corsika::process```
-    - All classes and objects are encapsulated into suited sub-namespaces,
-      thus corsika, corsikaes, corsika::units, etc.
-    - Namespace names do not use capital letters.  
-    - Every header file is copied during build and install into
-      "include/corsika/[namespace]" which also means, each header file
-      can only provide definitions for a _single_ namespace. It is one
-      main purpose of namespaces to structure the location of header
-      files.
-    - Each header file uses an include protection that includes at
-      least the namespace name, and header file name, thus, `#ifndef
-      __include_geometry_Point_h__` or `#ifndef __geometry_Point_h__`,
-      or similar are acceptable.
-    - Header files should always be included with `<..>`, thus,
-      `#include <corsika/framework/geometry/Point.hpp>` since the build system
-      will always provide the correct include directives (and files
-      anyway cannot be found in file-system paths, which generally do
-      not follow the namespace naming conventions outlined
-      here).
-
-  - Header files are named after the main class (or object) they
-    define. This also means each header file name starts with a
-    capital letter.
-  
-
-## Coding rules
-
-  - Warnings should be fixed, when they appear on the system(s) currently used by the CI, by altering the code unless the warning originates from third-party code and cannot be fixed. In that case, the warning should be locally silenced with appropriate pragmas or by locally turning off warnings for that translation unit. 
-  - All unit tests must succeed on the specified systems/configurations on gitlab-ci. If tests fail, code is not merged.
-  - The unit test code coverage should not decrease due to a new merge request. 
-  - We use C++17 features wherever useful and helpful. 
-  - On any major error or malfunction we throw an exception. This is needed and required for complex physics and shower debugging.
-  - We never catch exceptions for error handling, there might be very few special exceptions from this. We need to discuss such cases.
-  - Everything that should not change should be ```const```
-  - Everything that does not need to be visible to the outside of a class/struct should be `private` or `protected`
-  - We prefer the use of references, wherever useful
-  - There cannot be any raw pointer in the interface of any class or object
-    exposed to outside users, there might be (technical) raw pointers for very special cases
-    inside of classes.
-  - (member)functions that do something (are not just getters/setters), model actions or transformations, and should therefore be verbs. Classes are nouns.
-  - When you contribute new code, or extend existing code, at the same time provide unit-tests for all functionality.
-  - When you contribute new physics algorithms, in addition you also need to provide a validation module (this is still TBD what exactly this means)
-  - Code must be documented with `doxygen` commands extensively -> MAKE THIS INVESTMENT OF YOUR TIME EARLY, IT REALLY HELPS
-  - There should not be any useless comments in code, in particular absolutely avoid to commit commented-out debug remnants
-  - Add sufficient and meaningful comments to the code (only in English)
-  
-## CMAKE formatting
-
-  - command are lower cases, e.g. ```set (...)```
-  - variables upper case, e.g. ```set (VAR1 Text)```
-
-Since cmake itself lacks structure almost entirely:
-  - put a space between command and start of parenthesis, e.g. ```command (...)``` 
-  - add two spaces for logical indent 
-    ```
-    if (condition)
-      do something
-    endif (condition)
-    ```
-  - break long lines to start with new keyword in new line (indented)
-    ```
-    install (
-      FILES ${CORSIKAstackinterface_HEADERS}
-      DESTINATION include/${CORSIKAstackinterface_NAMESPACE}
-      )  
-    ```
-  - add plenty of comments to all cmake code
-  - use expressive variables and functions
+## Coding rules, conventions and guidelines
+
+Please read the [Coding wiki page](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/-/wikis/Coding-Conventions-and-Guidelines).
+
 
 
 
 ## Release versioning scheme
 
-Releases of CORSIKA are thought to be the baseline for larger scale
-testing, and full production.  The releases are numbered as x.y.z,
-starting with x=8 form the gitlab c++ version. X will only be
-incremented for major design or physics changes. The y index is
-updated for new official releases that normally contain improved or
-enhanced physics performance, and may also contain normal interface
+Releases of CORSIKA 8 are thought to be the baseline for larger scale
+validation, and full production.  The releases are numbered as x.y.z,
+starting with x=8, which will not be changed for CORSIKA 8. The y index is
+updated for new releases that normally contain improved or
+enhanced physics performance, and also interface
 changes to accomodate improvements. The z index can be updated more
 frequently for bug fixes or new features. Changes in z will not
-contain (major) interface changes, thus, production code will remain
-fully compatible within changes of z.  Special releases of CORSIKA can
-also have a tag name from git, e.g. as in the "milestone1" release.
+contain interface changes, thus, production code will remain
+fully compatible within changes of z.  Special releases of CORSIKA will
+also have a release names.
 
 
 # How to become scientific author of the CORSIKA Project
 
 The CORSIKA Project decides on who becomes scientific author. The
-following conditions are clearly sufficient, but not all of them are
+following conditions are sufficient, but not all of them are
 required all the time:
   - responsibility for a particular functionality or software/management part 
   - have read and follow these [GUIDELINES](CONTRIBUTING.md)
   - active in the CORSIKA Project, that means responsive to
     discussions and problems in corsika-devel@list.kit.edu or on https//gitlab.ikp.kit.edu, 
-    of relevant *Issues*,
-    or in (phone) meetings
-  - agreement to the [COLLABORATION_AGREEMENT](COLLABORATION_AGREEMENT.md) is strictly required
-  - the members of the CORSIKA Project panel agree
+    of relevant *Issues*, or in (phone) meetings
+  - agreement to the [COLLABORATION_AGREEMENT](COLLABORATION_AGREEMENT.md) 
+  - the members of the CORSIKA Project must agree
diff --git a/FIXME.md b/FIXME.md
deleted file mode 100644
index 9a5acb220cba997c882604620a28a8014710fc9b..0000000000000000000000000000000000000000
--- a/FIXME.md
+++ /dev/null
@@ -1,5129 +0,0 @@
-#All files:
-
-1. In all files do `#define guards` -> `#pragma once` to get faster compile times
-2. Redefine the folder structure:
-
-
-```
-#include <corsika/coast/...>
-#include <hydra/...>
-
-corsika
-|-- cmake
-|   |-- CodeCoverage
-|   |-- CodeCoverage.cmake
-|   |-- CorsikaUtilities.cmake
-|   `-- FindPythia8.cmake
-|-- coast
-|   |-- COASTProcess.h
-|   |-- COASTStack.h
-|   `-- ParticleConversion.h
-|-- docs
-|-- |doxygen
-|   `-- Doxyfile.in
-|-- testing  
-| 
-|-- examples
-|   |-- boundary_example.cc
-|   |-- cascade_example.cc
-|   |-- cascade_proton_example.cc
-|   |-- CMakeLists.txt
-|   |-- geometry_example.cc
-|   |-- helix_example.cc
-|   |-- logger_example.cc
-|   |-- stack_example.cc
-|   |-- staticsequence_example.cc
-|   |-- stopping_power.cc
-|   `-- vertical_EAS.cc
-|-- environment
-|   |-- BaseExponential.h
-|   |-- DensityFunction.h
-|   |-- Environment.h
-|   |-- FlatExponential.h
-|   |-- HomogeneousMedium.h
-|   |-- IMediumModel.hpp
-|   |-- InhomogeneousMedium.h
-|   |-- LayeredSphericalAtmosphereBuilder.h
-|   |-- LinearApproximationIntegrator.h
-|   |-- NameModel.h
-|   |-- NuclearComposition.h
-|   |-- SlidingPlanarExponential.h
-|   `-- VolumeTreeNode.hpp
-|-- framework
-|   |-- cascade
-|   |   |-- Cascade.h
-|   |-- geometry
-|   |   |-- BaseTrajectory.h
-|   |   |-- BaseVector.h
-|   |   |-- CMakeLists.txt
-|   |   |-- CoordinateSystem.h
-|   |   |-- FourVector.h
-|   |   |-- Helix.h
-|   |   |-- Line.h
-|   |   |-- Plane.h
-|   |   |-- Point.h
-|   |   |-- QuantityVector.h
-|   |   |-- RootCoordinateSystem.h
-|   |   |-- Sphere.h
-|   |   |-- Trajectory.h
-|   |   |-- Vector.h
-|   |   `-- Volume.h
-|   |-- logging
-|   |   |-- BufferedSink.h
-|   |   |-- Logger.h
-|   |   |-- MessageOff.h
-|   |   |-- MessageOn.h
-|   |   |-- NoSink.h
-|   |   `-- Sink.h
-|   |-- Particles
-|   |   `-- ParticleProperties.h
-|   |-- ProcessSequence
-|   |   |-- BaseProcess.h
-|   |   |-- BoundaryCrossingProcess.h
-|   |   |-- ContinuousProcess.h
-|   |   |-- DecayProcess.h
-|   |   |-- InteractionProcess.h
-|   |   |-- ProcessReturn.h
-|   |   |-- ProcessSequence.h
-|   |   |-- ProcessSignature.h
-|   |   |-- SecondariesProcess.h
-|   |   `-- StackProcess.h
-|   |-- Random
-|   |   |-- CMakeLists.txt
-|   |   |-- ExponentialDistribution.h
-|   |   |-- RNGManager.h
-|   |   `-- UniformRealDistribution.h
-|   |-- StackInterface
-|   |   |-- CMakeLists.txt
-|   |   |-- CombinedStack.h
-|   |   |-- comp
-|   |   |-- ParticleBase.h
-|   |   |-- SecondaryView.h
-|   |   |-- Stack.dox
-|   |   |-- Stack.h
-|   |   `-- StackIteratorInterface.h
-|   |-- Testing
-|   |   |-- test{...}.cc
-|   |-- Units
-|   |   |-- CMakeLists.txt
-|   |   |-- PhysicalConstants.h
-|   |   |-- PhysicalUnits.h
-|   |   `-- testUnits.cc
-|   |-- Utilities
-|   |   |-- Bit.h
-|   |   |-- CMakeLists.txt
-|   |   |-- COMBoost.cc
-|   |   |-- COMBoost.h
-|   |   |-- CorsikaFenvDefault.cc
-|   |   |-- CorsikaFenvFallback.cc
-|   |   |-- CorsikaFenv.h
-|   |   |-- CorsikaFenvOSX.cc
-|   |   |-- MetaProgramming.h
-|   |   |-- sgn.h
-|   |   |-- Singleton.h
-|   |   |-- testCOMBoost.cc
-|   |   |-- testCorsikaFenv.cc
-|   |   `-- try_feenableexcept.cc
-|   `-- CMakeLists.txt
-|-- Main
-|   |-- CMakeLists.txt
-|   `-- shower.cc
-|-- nuc
-|   |-- DataSet04.dat
-|   |-- ExpDatabase_Fortran77_v04.tar.gz
-|   |-- input04.f
-|   |-- main04.f
-|   `-- Makefile_ifc
-|-- Processes
-|   |-- EnergyLoss
-|   |   |-- CMakeLists.txt
-|   |   |-- EnergyLoss.cc
-|   |   |-- EnergyLoss.h
-|   |   |-- Properties8.dat
-|   |   |-- ReadData.py
-|   |   `-- SummaryPropTable.dat
-|   |-- HadronicElasticModel
-|   |   |-- CMakeLists.txt
-|   |   |-- HadronicElasticModel.cc
-|   |   `-- HadronicElasticModel.h
-|   |-- NullModel
-|   |   |-- CMakeLists.txt
-|   |   |-- NullModel.cc
-|   |   |-- NullModel.h
-|   |   `-- testNullModel.cc
-|   |-- ObservationPlane
-|   |   |-- CMakeLists.txt
-|   |   |-- ObservationPlane.cc
-|   |   |-- ObservationPlane.h
-|   |   `-- testObservationPlane.cc
-|   |-- ParticleCut
-|   |   |-- CMakeLists.txt
-|   |   |-- ParticleCut.cc
-|   |   |-- ParticleCut.h
-|   |   `-- testParticleCut.cc
-|   |-- Pythia
-|   |   |-- CMakeLists.txt
-|   |   |-- Decay.cc
-|   |   |-- Decay.h
-|   |   |-- Interaction.cc
-|   |   |-- Interaction.h
-|   |   |-- Random.cc
-|   |   |-- Random.h
-|   |   `-- testPythia.cc
-|   |-- QGSJetII
-|   |   |-- CMakeLists.txt
-|   |   |-- code_generator.py
-|   |   |-- Interaction.cc
-|   |   |-- Interaction.h
-|   |   |-- ParticleConversion.cc
-|   |   |-- ParticleConversion.h
-|   |   |-- qgsjet-II-04.cc
-|   |   |-- qgsjet-II-04-codes.dat
-|   |   |-- qgsjet-II-04.f
-|   |   |-- qgsjet-II-04.h
-|   |   |-- QGSJetIIFragmentsStack.h
-|   |   |-- QGSJetIIStack.h
-|   |   `-- testQGSJetII.cc
-|   |-- Sibyll
-|   |   |-- CMakeLists.txt
-|   |   |-- code_generator.py
-|   |   |-- Decay.cc
-|   |   |-- Decay.h
-|   |   |-- gasdev.f
-|   |   |-- Interaction.cc
-|   |   |-- Interaction.h
-|   |   |-- NuclearInteraction.cc
-|   |   |-- NuclearInteraction.h
-|   |   |-- nuclib.f
-|   |   |-- nuclib.h
-|   |   |-- ParticleConversion.cc
-|   |   |-- ParticleConversion.h
-|   |   |-- rndm_dbl.f
-|   |   |-- SibStack.h
-|   |   |-- sibyll2.3c.cc
-|   |   |-- sibyll2.3c.f
-|   |   |-- sibyll2.3c.h
-|   |   |-- sibyll_codes.dat
-|   |   |-- signuc.f
-|   |   `-- testSibyll.cc
-|   |-- StackInspector
-|   |   |-- CMakeLists.txt
-|   |   |-- StackInspector.cc
-|   |   |-- StackInspector.h
-|   |   `-- testStackInspector.cc
-|   |-- SwitchProcess
-|   |   |-- CMakeLists.txt
-|   |   |-- SwitchProcess.h
-|   |   `-- testSwitchProcess.cc
-|   |-- TrackingLine
-|   |   |-- CMakeLists.txt
-|   |   |-- testTrackingLine.cc
-|   |   |-- testTrackingLineStack.h
-|   |   |-- TrackingLine.cc
-|   |   `-- TrackingLine.h
-|   |-- TrackWriter
-|   |   |-- CMakeLists.txt
-|   |   |-- TrackWriter.cc
-|   |   `-- TrackWriter.h
-|   |-- UrQMD
-|   |   |-- addpart.f
-|   |   |-- angdis.f
-|   |   |-- anndec.f
-|   |   |-- blockres.f
-|   |   |-- boxinc.f
-|   |   |-- boxprg.f
-|   |   |-- cascinit.f
-|   |   |-- CMakeLists.txt
-|   |   |-- colltab.f
-|   |   |-- coload.f
-|   |   |-- comnorm.f
-|   |   |-- comres.f
-|   |   |-- coms.f
-|   |   |-- comstr.f
-|   |   |-- comwid.f
-|   |   |-- Copyright
-|   |   |-- dectim.f
-|   |   |-- delpart.f
-|   |   |-- detbal.f
-|   |   |-- dwidth.f
-|   |   |-- error.f
-|   |   |-- freezeout.f
-|   |   |-- getmass.f
-|   |   |-- getspin.f
-|   |   |-- init.f
-|   |   |-- inputs.f
-|   |   |-- iso.f
-|   |   |-- ityp2pdg.f
-|   |   |-- jdecay2.f
-|   |   |-- make22.f
-|   |   |-- newpart.f
-|   |   |-- numrec.f
-|   |   |-- options.f
-|   |   |-- outcom.f
-|   |   |-- output.f
-|   |   |-- paulibl.f
-|   |   |-- proppot.f
-|   |   |-- README
-|   |   |-- saveinfo.f
-|   |   |-- scatter.f
-|   |   |-- siglookup.f
-|   |   |-- string.f
-|   |   |-- tabinit.f
-|   |   |-- testUrQMD.cc
-|   |   |-- UrQMD.cc
-|   |   |-- urqmd.f
-|   |   |-- UrQMD.h
-|   |   |-- urqmdInterface.F
-|   |   `-- whichres.f
-|   `-- CMakeLists.txt
-|-- Setup
-|   |-- CMakeLists.txt
-|   |-- SetupEnvironment.h
-|   |-- SetupLogger.h
-|   |-- SetupStack.h
-|   `-- SetupTrajectory.h
-|-- Stack
-|   |-- DummyStack
-|   |   |-- CMakeLists.txt
-|   |   `-- DummyStack.h
-|   |-- NuclearStackExtension
-|   |   |-- CMakeLists.txt
-|   |   |-- NuclearStackExtension.h
-|   |   `-- testNuclearStackExtension.cc
-|   |-- SuperStupidStack
-|   |   |-- CMakeLists.txt
-|   |   |-- SuperStupidStack.h
-|   |   `-- testSuperStupidStack.cc
-|   `-- CMakeLists.txt
-|-- ThirdParty
-|   |-- boost
-|   |   |-- algorithm
-|   |   |   |-- cxx11
-|   |   |   |   `-- all_of.hpp
-|   |   |   |-- string
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- case_conv.hpp
-|   |   |   |   |   |-- classification.hpp
-|   |   |   |   |   |-- finder.hpp
-|   |   |   |   |   |-- find_format_all.hpp
-|   |   |   |   |   |-- find_format.hpp
-|   |   |   |   |   |-- find_format_store.hpp
-|   |   |   |   |   |-- find_iterator.hpp
-|   |   |   |   |   |-- formatter.hpp
-|   |   |   |   |   |-- predicate.hpp
-|   |   |   |   |   |-- replace_storage.hpp
-|   |   |   |   |   |-- sequence.hpp
-|   |   |   |   |   |-- trim.hpp
-|   |   |   |   |   `-- util.hpp
-|   |   |   |   |-- std
-|   |   |   |   |   |-- list_traits.hpp
-|   |   |   |   |   |-- slist_traits.hpp
-|   |   |   |   |   `-- string_traits.hpp
-|   |   |   |   |-- case_conv.hpp
-|   |   |   |   |-- classification.hpp
-|   |   |   |   |-- compare.hpp
-|   |   |   |   |-- concept.hpp
-|   |   |   |   |-- config.hpp
-|   |   |   |   |-- constants.hpp
-|   |   |   |   |-- erase.hpp
-|   |   |   |   |-- finder.hpp
-|   |   |   |   |-- find_format.hpp
-|   |   |   |   |-- find.hpp
-|   |   |   |   |-- find_iterator.hpp
-|   |   |   |   |-- formatter.hpp
-|   |   |   |   |-- iter_find.hpp
-|   |   |   |   |-- join.hpp
-|   |   |   |   |-- predicate_facade.hpp
-|   |   |   |   |-- predicate.hpp
-|   |   |   |   |-- replace.hpp
-|   |   |   |   |-- sequence_traits.hpp
-|   |   |   |   |-- split.hpp
-|   |   |   |   |-- std_containers_traits.hpp
-|   |   |   |   |-- trim.hpp
-|   |   |   |   `-- yes_no_type.hpp
-|   |   |   `-- string.hpp
-|   |   |-- assign
-|   |   |   |-- assignment_exception.hpp
-|   |   |   `-- list_of.hpp
-|   |   |-- bind
-|   |   |   |-- apply.hpp
-|   |   |   |-- arg.hpp
-|   |   |   |-- bind_cc.hpp
-|   |   |   |-- bind.hpp
-|   |   |   |-- bind_mf2_cc.hpp
-|   |   |   |-- bind_mf_cc.hpp
-|   |   |   |-- bind_template.hpp
-|   |   |   |-- mem_fn_cc.hpp
-|   |   |   |-- mem_fn.hpp
-|   |   |   |-- mem_fn_template.hpp
-|   |   |   |-- mem_fn_vw.hpp
-|   |   |   |-- placeholders.hpp
-|   |   |   `-- storage.hpp
-|   |   |-- chrono
-|   |   |   |-- detail
-|   |   |   |   |-- inlined
-|   |   |   |   |   |-- mac
-|   |   |   |   |   |   |-- chrono.hpp
-|   |   |   |   |   |   |-- process_cpu_clocks.hpp
-|   |   |   |   |   |   `-- thread_clock.hpp
-|   |   |   |   |   |-- posix
-|   |   |   |   |   |   |-- chrono.hpp
-|   |   |   |   |   |   |-- process_cpu_clocks.hpp
-|   |   |   |   |   |   `-- thread_clock.hpp
-|   |   |   |   |   |-- win
-|   |   |   |   |   |   |-- chrono.hpp
-|   |   |   |   |   |   |-- process_cpu_clocks.hpp
-|   |   |   |   |   |   `-- thread_clock.hpp
-|   |   |   |   |   |-- chrono.hpp
-|   |   |   |   |   |-- process_cpu_clocks.hpp
-|   |   |   |   |   `-- thread_clock.hpp
-|   |   |   |   |-- is_evenly_divisible_by.hpp
-|   |   |   |   |-- static_assert.hpp
-|   |   |   |   `-- system.hpp
-|   |   |   |-- chrono.hpp
-|   |   |   |-- clock_string.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- duration.hpp
-|   |   |   |-- process_cpu_clocks.hpp
-|   |   |   |-- system_clocks.hpp
-|   |   |   |-- thread_clock.hpp
-|   |   |   `-- time_point.hpp
-|   |   |-- concept
-|   |   |   |-- detail
-|   |   |   |   |-- backward_compatibility.hpp
-|   |   |   |   |-- borland.hpp
-|   |   |   |   |-- concept_def.hpp
-|   |   |   |   |-- concept_undef.hpp
-|   |   |   |   |-- general.hpp
-|   |   |   |   |-- has_constraints.hpp
-|   |   |   |   `-- msvc.hpp
-|   |   |   |-- assert.hpp
-|   |   |   `-- usage.hpp
-|   |   |-- config
-|   |   |   |-- abi
-|   |   |   |   |-- borland_prefix.hpp
-|   |   |   |   |-- borland_suffix.hpp
-|   |   |   |   |-- msvc_prefix.hpp
-|   |   |   |   `-- msvc_suffix.hpp
-|   |   |   |-- compiler
-|   |   |   |   |-- borland.hpp
-|   |   |   |   |-- clang.hpp
-|   |   |   |   |-- codegear.hpp
-|   |   |   |   |-- comeau.hpp
-|   |   |   |   |-- common_edg.hpp
-|   |   |   |   |-- compaq_cxx.hpp
-|   |   |   |   |-- cray.hpp
-|   |   |   |   |-- diab.hpp
-|   |   |   |   |-- digitalmars.hpp
-|   |   |   |   |-- gcc.hpp
-|   |   |   |   |-- gcc_xml.hpp
-|   |   |   |   |-- greenhills.hpp
-|   |   |   |   |-- hp_acc.hpp
-|   |   |   |   |-- intel.hpp
-|   |   |   |   |-- kai.hpp
-|   |   |   |   |-- metrowerks.hpp
-|   |   |   |   |-- mpw.hpp
-|   |   |   |   |-- nvcc.hpp
-|   |   |   |   |-- pathscale.hpp
-|   |   |   |   |-- pgi.hpp
-|   |   |   |   |-- sgi_mipspro.hpp
-|   |   |   |   |-- sunpro_cc.hpp
-|   |   |   |   |-- vacpp.hpp
-|   |   |   |   |-- visualc.hpp
-|   |   |   |   |-- xlcpp.hpp
-|   |   |   |   `-- xlcpp_zos.hpp
-|   |   |   |-- detail
-|   |   |   |   |-- posix_features.hpp
-|   |   |   |   |-- select_compiler_config.hpp
-|   |   |   |   |-- select_platform_config.hpp
-|   |   |   |   |-- select_stdlib_config.hpp
-|   |   |   |   `-- suffix.hpp
-|   |   |   |-- no_tr1
-|   |   |   |   |-- cmath.hpp
-|   |   |   |   |-- complex.hpp
-|   |   |   |   |-- functional.hpp
-|   |   |   |   |-- memory.hpp
-|   |   |   |   `-- utility.hpp
-|   |   |   |-- platform
-|   |   |   |   |-- aix.hpp
-|   |   |   |   |-- amigaos.hpp
-|   |   |   |   |-- beos.hpp
-|   |   |   |   |-- bsd.hpp
-|   |   |   |   |-- cloudabi.hpp
-|   |   |   |   |-- cray.hpp
-|   |   |   |   |-- cygwin.hpp
-|   |   |   |   |-- haiku.hpp
-|   |   |   |   |-- hpux.hpp
-|   |   |   |   |-- irix.hpp
-|   |   |   |   |-- linux.hpp
-|   |   |   |   |-- macos.hpp
-|   |   |   |   |-- qnxnto.hpp
-|   |   |   |   |-- solaris.hpp
-|   |   |   |   |-- symbian.hpp
-|   |   |   |   |-- vms.hpp
-|   |   |   |   |-- vxworks.hpp
-|   |   |   |   |-- win32.hpp
-|   |   |   |   `-- zos.hpp
-|   |   |   |-- stdlib
-|   |   |   |   |-- dinkumware.hpp
-|   |   |   |   |-- libcomo.hpp
-|   |   |   |   |-- libcpp.hpp
-|   |   |   |   |-- libstdcpp3.hpp
-|   |   |   |   |-- modena.hpp
-|   |   |   |   |-- msl.hpp
-|   |   |   |   |-- roguewave.hpp
-|   |   |   |   |-- sgi.hpp
-|   |   |   |   |-- stlport.hpp
-|   |   |   |   |-- vacpp.hpp
-|   |   |   |   `-- xlcpp_zos.hpp
-|   |   |   |-- abi_prefix.hpp
-|   |   |   |-- abi_suffix.hpp
-|   |   |   |-- auto_link.hpp
-|   |   |   |-- header_deprecated.hpp
-|   |   |   |-- helper_macros.hpp
-|   |   |   |-- pragma_message.hpp
-|   |   |   |-- requires_threads.hpp
-|   |   |   |-- user.hpp
-|   |   |   |-- warning_disable.hpp
-|   |   |   `-- workaround.hpp
-|   |   |-- container
-|   |   |   |-- detail
-|   |   |   |   |-- addressof.hpp
-|   |   |   |   |-- algorithm.hpp
-|   |   |   |   |-- allocation_type.hpp
-|   |   |   |   |-- allocator_version_traits.hpp
-|   |   |   |   |-- alloc_helpers.hpp
-|   |   |   |   |-- compare_functors.hpp
-|   |   |   |   |-- config_begin.hpp
-|   |   |   |   |-- config_end.hpp
-|   |   |   |   |-- construct_in_place.hpp
-|   |   |   |   |-- destroyers.hpp
-|   |   |   |   |-- iterator.hpp
-|   |   |   |   |-- iterators.hpp
-|   |   |   |   |-- mpl.hpp
-|   |   |   |   |-- multiallocation_chain.hpp
-|   |   |   |   |-- node_alloc_holder.hpp
-|   |   |   |   |-- placement_new.hpp
-|   |   |   |   |-- std_fwd.hpp
-|   |   |   |   |-- transform_iterator.hpp
-|   |   |   |   |-- type_traits.hpp
-|   |   |   |   |-- value_functors.hpp
-|   |   |   |   |-- value_init.hpp
-|   |   |   |   |-- variadic_templates_tools.hpp
-|   |   |   |   |-- version_type.hpp
-|   |   |   |   `-- workaround.hpp
-|   |   |   |-- allocator_traits.hpp
-|   |   |   |-- container_fwd.hpp
-|   |   |   |-- new_allocator.hpp
-|   |   |   |-- slist.hpp
-|   |   |   `-- throw_exception.hpp
-|   |   |-- container_hash
-|   |   |   |-- detail
-|   |   |   |   |-- float_functions.hpp
-|   |   |   |   |-- hash_float.hpp
-|   |   |   |   `-- limits.hpp
-|   |   |   |-- extensions.hpp
-|   |   |   |-- hash_fwd.hpp
-|   |   |   `-- hash.hpp
-|   |   |-- core
-|   |   |   |-- addressof.hpp
-|   |   |   |-- checked_delete.hpp
-|   |   |   |-- demangle.hpp
-|   |   |   |-- empty_value.hpp
-|   |   |   |-- enable_if.hpp
-|   |   |   |-- exchange.hpp
-|   |   |   |-- explicit_operator_bool.hpp
-|   |   |   |-- ignore_unused.hpp
-|   |   |   |-- is_same.hpp
-|   |   |   |-- lightweight_test.hpp
-|   |   |   |-- lightweight_test_trait.hpp
-|   |   |   |-- no_exceptions_support.hpp
-|   |   |   |-- noncopyable.hpp
-|   |   |   |-- null_deleter.hpp
-|   |   |   |-- pointer_traits.hpp
-|   |   |   |-- quick_exit.hpp
-|   |   |   |-- ref.hpp
-|   |   |   |-- scoped_enum.hpp
-|   |   |   |-- swap.hpp
-|   |   |   |-- typeinfo.hpp
-|   |   |   |-- uncaught_exceptions.hpp
-|   |   |   |-- underlying_type.hpp
-|   |   |   `-- use_default.hpp
-|   |   |-- detail
-|   |   |   |-- winapi
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- deprecated_namespace.hpp
-|   |   |   |   |-- get_current_process.hpp
-|   |   |   |   |-- get_current_thread.hpp
-|   |   |   |   |-- get_last_error.hpp
-|   |   |   |   |-- get_process_times.hpp
-|   |   |   |   `-- get_thread_times.hpp
-|   |   |   |-- basic_pointerbuf.hpp
-|   |   |   |-- bitmask.hpp
-|   |   |   |-- call_traits.hpp
-|   |   |   |-- container_fwd.hpp
-|   |   |   |-- fenv.hpp
-|   |   |   |-- indirect_traits.hpp
-|   |   |   |-- is_incrementable.hpp
-|   |   |   |-- iterator.hpp
-|   |   |   |-- lcast_precision.hpp
-|   |   |   |-- lightweight_test.hpp
-|   |   |   |-- numeric_traits.hpp
-|   |   |   |-- reference_content.hpp
-|   |   |   |-- select_type.hpp
-|   |   |   |-- sp_typeinfo.hpp
-|   |   |   |-- templated_streams.hpp
-|   |   |   |-- utf8_codecvt_facet.hpp
-|   |   |   |-- utf8_codecvt_facet.ipp
-|   |   |   `-- workaround.hpp
-|   |   |-- exception
-|   |   |   |-- detail
-|   |   |   |   |-- error_info_impl.hpp
-|   |   |   |   |-- is_output_streamable.hpp
-|   |   |   |   |-- object_hex_dump.hpp
-|   |   |   |   |-- shared_ptr.hpp
-|   |   |   |   `-- type_info.hpp
-|   |   |   |-- current_exception_cast.hpp
-|   |   |   |-- diagnostic_information.hpp
-|   |   |   |-- exception.hpp
-|   |   |   |-- get_error_info.hpp
-|   |   |   |-- info.hpp
-|   |   |   |-- to_string.hpp
-|   |   |   `-- to_string_stub.hpp
-|   |   |-- filesystem
-|   |   |   |-- detail
-|   |   |   |   `-- utf8_codecvt_facet.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- convenience.hpp
-|   |   |   |-- fstream.hpp
-|   |   |   |-- operations.hpp
-|   |   |   |-- path.hpp
-|   |   |   |-- path_traits.hpp
-|   |   |   `-- string_file.hpp
-|   |   |-- format
-|   |   |   |-- detail
-|   |   |   |   |-- compat_workarounds.hpp
-|   |   |   |   |-- config_macros.hpp
-|   |   |   |   |-- msvc_disambiguater.hpp
-|   |   |   |   |-- unset_macros.hpp
-|   |   |   |   |-- workarounds_gcc-2_95.hpp
-|   |   |   |   `-- workarounds_stlport.hpp
-|   |   |   |-- alt_sstream.hpp
-|   |   |   |-- alt_sstream_impl.hpp
-|   |   |   |-- exceptions.hpp
-|   |   |   |-- feed_args.hpp
-|   |   |   |-- format_class.hpp
-|   |   |   |-- format_fwd.hpp
-|   |   |   |-- format_implementation.hpp
-|   |   |   |-- free_funcs.hpp
-|   |   |   |-- group.hpp
-|   |   |   |-- internals_fwd.hpp
-|   |   |   |-- internals.hpp
-|   |   |   `-- parsing.hpp
-|   |   |-- function
-|   |   |   |-- detail
-|   |   |   |   |-- function_iterate.hpp
-|   |   |   |   |-- gen_maybe_include.pl
-|   |   |   |   |-- maybe_include.hpp
-|   |   |   |   `-- prologue.hpp
-|   |   |   |-- function0.hpp
-|   |   |   |-- function10.hpp
-|   |   |   |-- function1.hpp
-|   |   |   |-- function2.hpp
-|   |   |   |-- function3.hpp
-|   |   |   |-- function4.hpp
-|   |   |   |-- function5.hpp
-|   |   |   |-- function6.hpp
-|   |   |   |-- function7.hpp
-|   |   |   |-- function8.hpp
-|   |   |   |-- function9.hpp
-|   |   |   |-- function_base.hpp
-|   |   |   |-- function_fwd.hpp
-|   |   |   `-- function_template.hpp
-|   |   |-- functional
-|   |   |   `-- hash_fwd.hpp
-|   |   |-- function_types
-|   |   |   |-- config
-|   |   |   |   |-- cc_names.hpp
-|   |   |   |   |-- compiler.hpp
-|   |   |   |   `-- config.hpp
-|   |   |   |-- detail
-|   |   |   |   |-- classifier_impl
-|   |   |   |   |   |-- arity10_0.hpp
-|   |   |   |   |   |-- arity10_1.hpp
-|   |   |   |   |   |-- arity20_0.hpp
-|   |   |   |   |   |-- arity20_1.hpp
-|   |   |   |   |   |-- arity30_0.hpp
-|   |   |   |   |   |-- arity30_1.hpp
-|   |   |   |   |   |-- arity40_0.hpp
-|   |   |   |   |   |-- arity40_1.hpp
-|   |   |   |   |   |-- arity50_0.hpp
-|   |   |   |   |   |-- arity50_1.hpp
-|   |   |   |   |   `-- master.hpp
-|   |   |   |   |-- components_impl
-|   |   |   |   |   |-- arity10_0.hpp
-|   |   |   |   |   |-- arity10_1.hpp
-|   |   |   |   |   |-- arity20_0.hpp
-|   |   |   |   |   |-- arity20_1.hpp
-|   |   |   |   |   |-- arity30_0.hpp
-|   |   |   |   |   |-- arity30_1.hpp
-|   |   |   |   |   |-- arity40_0.hpp
-|   |   |   |   |   |-- arity40_1.hpp
-|   |   |   |   |   |-- arity50_0.hpp
-|   |   |   |   |   |-- arity50_1.hpp
-|   |   |   |   |   `-- master.hpp
-|   |   |   |   |-- encoding
-|   |   |   |   |   |-- aliases_def.hpp
-|   |   |   |   |   |-- aliases_undef.hpp
-|   |   |   |   |   |-- def.hpp
-|   |   |   |   |   `-- undef.hpp
-|   |   |   |   |-- pp_cc_loop
-|   |   |   |   |   |-- master.hpp
-|   |   |   |   |   `-- preprocessed.hpp
-|   |   |   |   |-- pp_retag_default_cc
-|   |   |   |   |   |-- master.hpp
-|   |   |   |   |   `-- preprocessed.hpp
-|   |   |   |   |-- pp_tags
-|   |   |   |   |   |-- cc_tag.hpp
-|   |   |   |   |   |-- master.hpp
-|   |   |   |   |   `-- preprocessed.hpp
-|   |   |   |   |-- pp_variate_loop
-|   |   |   |   |   |-- master.hpp
-|   |   |   |   |   `-- preprocessed.hpp
-|   |   |   |   |-- synthesize_impl
-|   |   |   |   |   |-- arity10_0.hpp
-|   |   |   |   |   |-- arity10_1.hpp
-|   |   |   |   |   |-- arity20_0.hpp
-|   |   |   |   |   |-- arity20_1.hpp
-|   |   |   |   |   |-- arity30_0.hpp
-|   |   |   |   |   |-- arity30_1.hpp
-|   |   |   |   |   |-- arity40_0.hpp
-|   |   |   |   |   |-- arity40_1.hpp
-|   |   |   |   |   |-- arity50_0.hpp
-|   |   |   |   |   |-- arity50_1.hpp
-|   |   |   |   |   `-- master.hpp
-|   |   |   |   |-- classifier.hpp
-|   |   |   |   |-- class_transform.hpp
-|   |   |   |   |-- components_as_mpl_sequence.hpp
-|   |   |   |   |-- cv_traits.hpp
-|   |   |   |   |-- pp_arity_loop.hpp
-|   |   |   |   |-- pp_loop.hpp
-|   |   |   |   |-- retag_default_cc.hpp
-|   |   |   |   |-- synthesize.hpp
-|   |   |   |   `-- to_sequence.hpp
-|   |   |   |-- components.hpp
-|   |   |   |-- is_callable_builtin.hpp
-|   |   |   |-- is_function_pointer.hpp
-|   |   |   |-- property_tags.hpp
-|   |   |   `-- result_type.hpp
-|   |   |-- fusion
-|   |   |   |-- adapted
-|   |   |   |   |-- boost_tuple
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- build_cons.hpp
-|   |   |   |   |   |   |-- category_of_impl.hpp
-|   |   |   |   |   |   |-- convert_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- is_sequence_impl.hpp
-|   |   |   |   |   |   |-- is_view_impl.hpp
-|   |   |   |   |   |   |-- size_impl.hpp
-|   |   |   |   |   |   `-- value_at_impl.hpp
-|   |   |   |   |   |-- mpl
-|   |   |   |   |   |   `-- clear.hpp
-|   |   |   |   |   |-- boost_tuple_iterator.hpp
-|   |   |   |   |   `-- tag_of.hpp
-|   |   |   |   |-- mpl
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- category_of_impl.hpp
-|   |   |   |   |   |   |-- empty_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- has_key_impl.hpp
-|   |   |   |   |   |   |-- is_sequence_impl.hpp
-|   |   |   |   |   |   |-- is_view_impl.hpp
-|   |   |   |   |   |   |-- size_impl.hpp
-|   |   |   |   |   |   `-- value_at_impl.hpp
-|   |   |   |   |   `-- mpl_iterator.hpp
-|   |   |   |   |-- std_tuple
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- build_std_tuple.hpp
-|   |   |   |   |   |   |-- category_of_impl.hpp
-|   |   |   |   |   |   |-- convert_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- is_sequence_impl.hpp
-|   |   |   |   |   |   |-- is_view_impl.hpp
-|   |   |   |   |   |   |-- size_impl.hpp
-|   |   |   |   |   |   `-- value_at_impl.hpp
-|   |   |   |   |   |-- mpl
-|   |   |   |   |   |   `-- clear.hpp
-|   |   |   |   |   |-- std_tuple_iterator.hpp
-|   |   |   |   |   `-- tag_of.hpp
-|   |   |   |   |-- struct
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- preprocessor
-|   |   |   |   |   |   |   `-- is_seq.hpp
-|   |   |   |   |   |   |-- adapt_auto.hpp
-|   |   |   |   |   |   |-- adapt_base_attr_filler.hpp
-|   |   |   |   |   |   |-- adapt_base.hpp
-|   |   |   |   |   |   |-- adapt_is_tpl.hpp
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- category_of_impl.hpp
-|   |   |   |   |   |   |-- deref_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- extension.hpp
-|   |   |   |   |   |   |-- is_sequence_impl.hpp
-|   |   |   |   |   |   |-- is_view_impl.hpp
-|   |   |   |   |   |   |-- size_impl.hpp
-|   |   |   |   |   |   |-- value_at_impl.hpp
-|   |   |   |   |   |   `-- value_of_impl.hpp
-|   |   |   |   |   `-- adapt_struct.hpp
-|   |   |   |   |-- boost_tuple.hpp
-|   |   |   |   |-- mpl.hpp
-|   |   |   |   |-- std_pair.hpp
-|   |   |   |   `-- std_tuple.hpp
-|   |   |   |-- algorithm
-|   |   |   |   |-- iteration
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   |   `-- fold.hpp
-|   |   |   |   |   |   |-- fold.hpp
-|   |   |   |   |   |   |-- for_each.hpp
-|   |   |   |   |   |   |-- segmented_fold.hpp
-|   |   |   |   |   |   `-- segmented_for_each.hpp
-|   |   |   |   |   |-- fold_fwd.hpp
-|   |   |   |   |   |-- fold.hpp
-|   |   |   |   |   |-- for_each_fwd.hpp
-|   |   |   |   |   `-- for_each.hpp
-|   |   |   |   |-- query
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- find_if.hpp
-|   |   |   |   |   |   `-- segmented_find.hpp
-|   |   |   |   |   |-- find_fwd.hpp
-|   |   |   |   |   |-- find.hpp
-|   |   |   |   |   `-- find_if_fwd.hpp
-|   |   |   |   `-- transformation
-|   |   |   |       |-- erase.hpp
-|   |   |   |       |-- erase_key.hpp
-|   |   |   |       |-- insert.hpp
-|   |   |   |       |-- insert_range.hpp
-|   |   |   |       |-- pop_back.hpp
-|   |   |   |       |-- pop_front.hpp
-|   |   |   |       |-- push_back.hpp
-|   |   |   |       |-- push_front.hpp
-|   |   |   |       `-- transform.hpp
-|   |   |   |-- container
-|   |   |   |   |-- deque
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- cpp03
-|   |   |   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   |   |   |-- as_deque10.hpp
-|   |   |   |   |   |   |   |   |-- as_deque20.hpp
-|   |   |   |   |   |   |   |   |-- as_deque30.hpp
-|   |   |   |   |   |   |   |   |-- as_deque40.hpp
-|   |   |   |   |   |   |   |   |-- as_deque50.hpp
-|   |   |   |   |   |   |   |   |-- as_deque.hpp
-|   |   |   |   |   |   |   |   |-- deque10_fwd.hpp
-|   |   |   |   |   |   |   |   |-- deque10.hpp
-|   |   |   |   |   |   |   |   |-- deque20_fwd.hpp
-|   |   |   |   |   |   |   |   |-- deque20.hpp
-|   |   |   |   |   |   |   |   |-- deque30_fwd.hpp
-|   |   |   |   |   |   |   |   |-- deque30.hpp
-|   |   |   |   |   |   |   |   |-- deque40_fwd.hpp
-|   |   |   |   |   |   |   |   |-- deque40.hpp
-|   |   |   |   |   |   |   |   |-- deque50_fwd.hpp
-|   |   |   |   |   |   |   |   |-- deque50.hpp
-|   |   |   |   |   |   |   |   |-- deque_fwd.hpp
-|   |   |   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |   |   |-- deque_initial_size10.hpp
-|   |   |   |   |   |   |   |   |-- deque_initial_size20.hpp
-|   |   |   |   |   |   |   |   |-- deque_initial_size30.hpp
-|   |   |   |   |   |   |   |   |-- deque_initial_size40.hpp
-|   |   |   |   |   |   |   |   |-- deque_initial_size50.hpp
-|   |   |   |   |   |   |   |   |-- deque_initial_size.hpp
-|   |   |   |   |   |   |   |   |-- deque_keyed_values10.hpp
-|   |   |   |   |   |   |   |   |-- deque_keyed_values20.hpp
-|   |   |   |   |   |   |   |   |-- deque_keyed_values30.hpp
-|   |   |   |   |   |   |   |   |-- deque_keyed_values40.hpp
-|   |   |   |   |   |   |   |   |-- deque_keyed_values50.hpp
-|   |   |   |   |   |   |   |   `-- deque_keyed_values.hpp
-|   |   |   |   |   |   |   |-- as_deque.hpp
-|   |   |   |   |   |   |   |-- build_deque.hpp
-|   |   |   |   |   |   |   |-- deque_forward_ctor.hpp
-|   |   |   |   |   |   |   |-- deque_fwd.hpp
-|   |   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |   |-- deque_initial_size.hpp
-|   |   |   |   |   |   |   |-- deque_keyed_values_call.hpp
-|   |   |   |   |   |   |   |-- deque_keyed_values.hpp
-|   |   |   |   |   |   |   `-- limits.hpp
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- build_deque.hpp
-|   |   |   |   |   |   |-- convert_impl.hpp
-|   |   |   |   |   |   |-- deque_keyed_values.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- is_sequence_impl.hpp
-|   |   |   |   |   |   |-- keyed_element.hpp
-|   |   |   |   |   |   `-- value_at_impl.hpp
-|   |   |   |   |   |-- back_extended_deque.hpp
-|   |   |   |   |   |-- convert.hpp
-|   |   |   |   |   |-- deque_fwd.hpp
-|   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |-- deque_iterator.hpp
-|   |   |   |   |   `-- front_extended_deque.hpp
-|   |   |   |   |-- generation
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   |   |-- make_deque10.hpp
-|   |   |   |   |   |   |   |-- make_deque20.hpp
-|   |   |   |   |   |   |   |-- make_deque30.hpp
-|   |   |   |   |   |   |   |-- make_deque40.hpp
-|   |   |   |   |   |   |   |-- make_deque50.hpp
-|   |   |   |   |   |   |   |-- make_deque.hpp
-|   |   |   |   |   |   |   |-- make_list10.hpp
-|   |   |   |   |   |   |   |-- make_list20.hpp
-|   |   |   |   |   |   |   |-- make_list30.hpp
-|   |   |   |   |   |   |   |-- make_list40.hpp
-|   |   |   |   |   |   |   |-- make_list50.hpp
-|   |   |   |   |   |   |   |-- make_list.hpp
-|   |   |   |   |   |   |   |-- make_vector10.hpp
-|   |   |   |   |   |   |   |-- make_vector20.hpp
-|   |   |   |   |   |   |   |-- make_vector30.hpp
-|   |   |   |   |   |   |   |-- make_vector40.hpp
-|   |   |   |   |   |   |   |-- make_vector50.hpp
-|   |   |   |   |   |   |   `-- make_vector.hpp
-|   |   |   |   |   |   |-- pp_make_deque.hpp
-|   |   |   |   |   |   |-- pp_make_list.hpp
-|   |   |   |   |   |   `-- pp_make_vector.hpp
-|   |   |   |   |   |-- make_deque.hpp
-|   |   |   |   |   |-- make_list.hpp
-|   |   |   |   |   `-- make_vector.hpp
-|   |   |   |   |-- list
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- cpp03
-|   |   |   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   |   |   |-- list10_fwd.hpp
-|   |   |   |   |   |   |   |   |-- list10.hpp
-|   |   |   |   |   |   |   |   |-- list20_fwd.hpp
-|   |   |   |   |   |   |   |   |-- list20.hpp
-|   |   |   |   |   |   |   |   |-- list30_fwd.hpp
-|   |   |   |   |   |   |   |   |-- list30.hpp
-|   |   |   |   |   |   |   |   |-- list40_fwd.hpp
-|   |   |   |   |   |   |   |   |-- list40.hpp
-|   |   |   |   |   |   |   |   |-- list50_fwd.hpp
-|   |   |   |   |   |   |   |   |-- list50.hpp
-|   |   |   |   |   |   |   |   |-- list_fwd.hpp
-|   |   |   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |   |   |-- list_to_cons10.hpp
-|   |   |   |   |   |   |   |   |-- list_to_cons20.hpp
-|   |   |   |   |   |   |   |   |-- list_to_cons30.hpp
-|   |   |   |   |   |   |   |   |-- list_to_cons40.hpp
-|   |   |   |   |   |   |   |   |-- list_to_cons50.hpp
-|   |   |   |   |   |   |   |   `-- list_to_cons.hpp
-|   |   |   |   |   |   |   |-- limits.hpp
-|   |   |   |   |   |   |   |-- list_forward_ctor.hpp
-|   |   |   |   |   |   |   |-- list_fwd.hpp
-|   |   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |   |-- list_to_cons_call.hpp
-|   |   |   |   |   |   |   `-- list_to_cons.hpp
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- build_cons.hpp
-|   |   |   |   |   |   |-- convert_impl.hpp
-|   |   |   |   |   |   |-- deref_impl.hpp
-|   |   |   |   |   |   |-- empty_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- equal_to_impl.hpp
-|   |   |   |   |   |   |-- list_to_cons.hpp
-|   |   |   |   |   |   |-- next_impl.hpp
-|   |   |   |   |   |   |-- reverse_cons.hpp
-|   |   |   |   |   |   |-- value_at_impl.hpp
-|   |   |   |   |   |   `-- value_of_impl.hpp
-|   |   |   |   |   |-- cons_fwd.hpp
-|   |   |   |   |   |-- cons.hpp
-|   |   |   |   |   |-- cons_iterator.hpp
-|   |   |   |   |   |-- convert.hpp
-|   |   |   |   |   |-- list_fwd.hpp
-|   |   |   |   |   |-- list.hpp
-|   |   |   |   |   `-- nil.hpp
-|   |   |   |   |-- map
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   `-- cpp03
-|   |   |   |   |   |       |-- preprocessed
-|   |   |   |   |   |       |   |-- map10_fwd.hpp
-|   |   |   |   |   |       |   |-- map20_fwd.hpp
-|   |   |   |   |   |       |   |-- map30_fwd.hpp
-|   |   |   |   |   |       |   |-- map40_fwd.hpp
-|   |   |   |   |   |       |   |-- map50_fwd.hpp
-|   |   |   |   |   |       |   `-- map_fwd.hpp
-|   |   |   |   |   |       |-- limits.hpp
-|   |   |   |   |   |       `-- map_fwd.hpp
-|   |   |   |   |   `-- map_fwd.hpp
-|   |   |   |   |-- set
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   `-- cpp03
-|   |   |   |   |   |       |-- preprocessed
-|   |   |   |   |   |       |   |-- set10_fwd.hpp
-|   |   |   |   |   |       |   |-- set20_fwd.hpp
-|   |   |   |   |   |       |   |-- set30_fwd.hpp
-|   |   |   |   |   |       |   |-- set40_fwd.hpp
-|   |   |   |   |   |       |   |-- set50_fwd.hpp
-|   |   |   |   |   |       |   `-- set_fwd.hpp
-|   |   |   |   |   |       |-- limits.hpp
-|   |   |   |   |   |       `-- set_fwd.hpp
-|   |   |   |   |   `-- set_fwd.hpp
-|   |   |   |   |-- vector
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- cpp03
-|   |   |   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   |   |   |-- as_vector10.hpp
-|   |   |   |   |   |   |   |   |-- as_vector20.hpp
-|   |   |   |   |   |   |   |   |-- as_vector30.hpp
-|   |   |   |   |   |   |   |   |-- as_vector40.hpp
-|   |   |   |   |   |   |   |   |-- as_vector50.hpp
-|   |   |   |   |   |   |   |   |-- as_vector.hpp
-|   |   |   |   |   |   |   |   |-- vector10_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vector10.hpp
-|   |   |   |   |   |   |   |   |-- vector20_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vector20.hpp
-|   |   |   |   |   |   |   |   |-- vector30_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vector30.hpp
-|   |   |   |   |   |   |   |   |-- vector40_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vector40.hpp
-|   |   |   |   |   |   |   |   |-- vector50_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vector50.hpp
-|   |   |   |   |   |   |   |   |-- vector_chooser10.hpp
-|   |   |   |   |   |   |   |   |-- vector_chooser20.hpp
-|   |   |   |   |   |   |   |   |-- vector_chooser30.hpp
-|   |   |   |   |   |   |   |   |-- vector_chooser40.hpp
-|   |   |   |   |   |   |   |   |-- vector_chooser50.hpp
-|   |   |   |   |   |   |   |   |-- vector_chooser.hpp
-|   |   |   |   |   |   |   |   |-- vector_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vector.hpp
-|   |   |   |   |   |   |   |   |-- vvector10_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vvector10.hpp
-|   |   |   |   |   |   |   |   |-- vvector20_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vvector20.hpp
-|   |   |   |   |   |   |   |   |-- vvector30_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vvector30.hpp
-|   |   |   |   |   |   |   |   |-- vvector40_fwd.hpp
-|   |   |   |   |   |   |   |   |-- vvector40.hpp
-|   |   |   |   |   |   |   |   |-- vvector50_fwd.hpp
-|   |   |   |   |   |   |   |   `-- vvector50.hpp
-|   |   |   |   |   |   |   |-- as_vector.hpp
-|   |   |   |   |   |   |   |-- limits.hpp
-|   |   |   |   |   |   |   |-- value_at_impl.hpp
-|   |   |   |   |   |   |   |-- vector10_fwd.hpp
-|   |   |   |   |   |   |   |-- vector10.hpp
-|   |   |   |   |   |   |   |-- vector20_fwd.hpp
-|   |   |   |   |   |   |   |-- vector20.hpp
-|   |   |   |   |   |   |   |-- vector30_fwd.hpp
-|   |   |   |   |   |   |   |-- vector30.hpp
-|   |   |   |   |   |   |   |-- vector40_fwd.hpp
-|   |   |   |   |   |   |   |-- vector40.hpp
-|   |   |   |   |   |   |   |-- vector50_fwd.hpp
-|   |   |   |   |   |   |   |-- vector50.hpp
-|   |   |   |   |   |   |   |-- vector_forward_ctor.hpp
-|   |   |   |   |   |   |   |-- vector_fwd.hpp
-|   |   |   |   |   |   |   |-- vector.hpp
-|   |   |   |   |   |   |   |-- vector_n_chooser.hpp
-|   |   |   |   |   |   |   `-- vector_n.hpp
-|   |   |   |   |   |   |-- advance_impl.hpp
-|   |   |   |   |   |   |-- as_vector.hpp
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- config.hpp
-|   |   |   |   |   |   |-- convert_impl.hpp
-|   |   |   |   |   |   |-- deref_impl.hpp
-|   |   |   |   |   |   |-- distance_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- equal_to_impl.hpp
-|   |   |   |   |   |   |-- next_impl.hpp
-|   |   |   |   |   |   |-- prior_impl.hpp
-|   |   |   |   |   |   |-- value_at_impl.hpp
-|   |   |   |   |   |   `-- value_of_impl.hpp
-|   |   |   |   |   |-- convert.hpp
-|   |   |   |   |   |-- vector10.hpp
-|   |   |   |   |   |-- vector_fwd.hpp
-|   |   |   |   |   |-- vector.hpp
-|   |   |   |   |   `-- vector_iterator.hpp
-|   |   |   |   |-- deque.hpp
-|   |   |   |   |-- list.hpp
-|   |   |   |   `-- vector.hpp
-|   |   |   |-- include
-|   |   |   |   |-- at.hpp
-|   |   |   |   |-- deque.hpp
-|   |   |   |   |-- list.hpp
-|   |   |   |   |-- make_deque.hpp
-|   |   |   |   |-- make_list.hpp
-|   |   |   |   |-- make_vector.hpp
-|   |   |   |   `-- vector.hpp
-|   |   |   |-- iterator
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- adapt_deref_traits.hpp
-|   |   |   |   |   |-- adapt_value_traits.hpp
-|   |   |   |   |   |-- advance.hpp
-|   |   |   |   |   |-- distance.hpp
-|   |   |   |   |   |-- segmented_equal_to.hpp
-|   |   |   |   |   |-- segmented_iterator.hpp
-|   |   |   |   |   |-- segmented_next_impl.hpp
-|   |   |   |   |   `-- segment_sequence.hpp
-|   |   |   |   |-- mpl
-|   |   |   |   |   |-- convert_iterator.hpp
-|   |   |   |   |   `-- fusion_iterator.hpp
-|   |   |   |   |-- advance.hpp
-|   |   |   |   |-- basic_iterator.hpp
-|   |   |   |   |-- deref_data.hpp
-|   |   |   |   |-- deref.hpp
-|   |   |   |   |-- distance.hpp
-|   |   |   |   |-- equal_to.hpp
-|   |   |   |   |-- iterator_adapter.hpp
-|   |   |   |   |-- iterator_facade.hpp
-|   |   |   |   |-- key_of.hpp
-|   |   |   |   |-- mpl.hpp
-|   |   |   |   |-- next.hpp
-|   |   |   |   |-- prior.hpp
-|   |   |   |   |-- segmented_iterator.hpp
-|   |   |   |   |-- value_of_data.hpp
-|   |   |   |   `-- value_of.hpp
-|   |   |   |-- mpl
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- clear.hpp
-|   |   |   |   |-- at.hpp
-|   |   |   |   |-- back.hpp
-|   |   |   |   |-- begin.hpp
-|   |   |   |   |-- clear.hpp
-|   |   |   |   |-- empty.hpp
-|   |   |   |   |-- end.hpp
-|   |   |   |   |-- erase.hpp
-|   |   |   |   |-- erase_key.hpp
-|   |   |   |   |-- front.hpp
-|   |   |   |   |-- has_key.hpp
-|   |   |   |   |-- insert.hpp
-|   |   |   |   |-- insert_range.hpp
-|   |   |   |   |-- pop_back.hpp
-|   |   |   |   |-- pop_front.hpp
-|   |   |   |   |-- push_back.hpp
-|   |   |   |   |-- push_front.hpp
-|   |   |   |   `-- size.hpp
-|   |   |   |-- sequence
-|   |   |   |   |-- comparison
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   `-- equal_to.hpp
-|   |   |   |   |   |-- enable_comparison.hpp
-|   |   |   |   |   `-- equal_to.hpp
-|   |   |   |   |-- intrinsic
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- segmented_begin.hpp
-|   |   |   |   |   |   |-- segmented_begin_impl.hpp
-|   |   |   |   |   |   |-- segmented_end.hpp
-|   |   |   |   |   |   |-- segmented_end_impl.hpp
-|   |   |   |   |   |   `-- segmented_size.hpp
-|   |   |   |   |   |-- at_c.hpp
-|   |   |   |   |   |-- at.hpp
-|   |   |   |   |   |-- begin.hpp
-|   |   |   |   |   |-- empty.hpp
-|   |   |   |   |   |-- end.hpp
-|   |   |   |   |   |-- has_key.hpp
-|   |   |   |   |   |-- segments.hpp
-|   |   |   |   |   |-- size.hpp
-|   |   |   |   |   `-- value_at.hpp
-|   |   |   |   |-- convert.hpp
-|   |   |   |   `-- intrinsic_fwd.hpp
-|   |   |   |-- support
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- access.hpp
-|   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |-- as_fusion_element.hpp
-|   |   |   |   |   |-- enabler.hpp
-|   |   |   |   |   |-- index_sequence.hpp
-|   |   |   |   |   |-- is_mpl_sequence.hpp
-|   |   |   |   |   |-- is_native_fusion_sequence.hpp
-|   |   |   |   |   |-- mpl_iterator_category.hpp
-|   |   |   |   |   |-- pp_round.hpp
-|   |   |   |   |   `-- segmented_fold_until_impl.hpp
-|   |   |   |   |-- as_const.hpp
-|   |   |   |   |-- category_of.hpp
-|   |   |   |   |-- config.hpp
-|   |   |   |   |-- is_iterator.hpp
-|   |   |   |   |-- is_segmented.hpp
-|   |   |   |   |-- is_sequence.hpp
-|   |   |   |   |-- is_view.hpp
-|   |   |   |   |-- iterator_base.hpp
-|   |   |   |   |-- segmented_fold_until.hpp
-|   |   |   |   |-- sequence_base.hpp
-|   |   |   |   |-- tag_of_fwd.hpp
-|   |   |   |   |-- tag_of.hpp
-|   |   |   |   `-- void.hpp
-|   |   |   |-- view
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- strictest_traversal.hpp
-|   |   |   |   |-- iterator_range
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- is_segmented_impl.hpp
-|   |   |   |   |   |   |-- segmented_iterator_range.hpp
-|   |   |   |   |   |   |-- segments_impl.hpp
-|   |   |   |   |   |   |-- size_impl.hpp
-|   |   |   |   |   |   `-- value_at_impl.hpp
-|   |   |   |   |   `-- iterator_range.hpp
-|   |   |   |   |-- joint_view
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- deref_data_impl.hpp
-|   |   |   |   |   |   |-- deref_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- key_of_impl.hpp
-|   |   |   |   |   |   |-- next_impl.hpp
-|   |   |   |   |   |   |-- value_of_data_impl.hpp
-|   |   |   |   |   |   `-- value_of_impl.hpp
-|   |   |   |   |   |-- joint_view_fwd.hpp
-|   |   |   |   |   |-- joint_view.hpp
-|   |   |   |   |   `-- joint_view_iterator.hpp
-|   |   |   |   |-- single_view
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- advance_impl.hpp
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- deref_impl.hpp
-|   |   |   |   |   |   |-- distance_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- equal_to_impl.hpp
-|   |   |   |   |   |   |-- next_impl.hpp
-|   |   |   |   |   |   |-- prior_impl.hpp
-|   |   |   |   |   |   |-- size_impl.hpp
-|   |   |   |   |   |   |-- value_at_impl.hpp
-|   |   |   |   |   |   `-- value_of_impl.hpp
-|   |   |   |   |   |-- single_view.hpp
-|   |   |   |   |   `-- single_view_iterator.hpp
-|   |   |   |   |-- transform_view
-|   |   |   |   |   |-- detail
-|   |   |   |   |   |   |-- advance_impl.hpp
-|   |   |   |   |   |   |-- at_impl.hpp
-|   |   |   |   |   |   |-- begin_impl.hpp
-|   |   |   |   |   |   |-- deref_impl.hpp
-|   |   |   |   |   |   |-- distance_impl.hpp
-|   |   |   |   |   |   |-- end_impl.hpp
-|   |   |   |   |   |   |-- equal_to_impl.hpp
-|   |   |   |   |   |   |-- next_impl.hpp
-|   |   |   |   |   |   |-- prior_impl.hpp
-|   |   |   |   |   |   |-- value_at_impl.hpp
-|   |   |   |   |   |   `-- value_of_impl.hpp
-|   |   |   |   |   |-- transform_view_fwd.hpp
-|   |   |   |   |   |-- transform_view.hpp
-|   |   |   |   |   `-- transform_view_iterator.hpp
-|   |   |   |   `-- iterator_range.hpp
-|   |   |   `-- mpl.hpp
-|   |   |-- integer
-|   |   |   |-- common_factor_rt.hpp
-|   |   |   `-- static_log2.hpp
-|   |   |-- intrusive
-|   |   |   |-- detail
-|   |   |   |   |-- algorithm.hpp
-|   |   |   |   |-- algo_type.hpp
-|   |   |   |   |-- array_initializer.hpp
-|   |   |   |   |-- assert.hpp
-|   |   |   |   |-- common_slist_algorithms.hpp
-|   |   |   |   |-- config_begin.hpp
-|   |   |   |   |-- config_end.hpp
-|   |   |   |   |-- default_header_holder.hpp
-|   |   |   |   |-- ebo_functor_holder.hpp
-|   |   |   |   |-- equal_to_value.hpp
-|   |   |   |   |-- exception_disposer.hpp
-|   |   |   |   |-- function_detector.hpp
-|   |   |   |   |-- generic_hook.hpp
-|   |   |   |   |-- get_value_traits.hpp
-|   |   |   |   |-- has_member_function_callable_with.hpp
-|   |   |   |   |-- hook_traits.hpp
-|   |   |   |   |-- iiterator.hpp
-|   |   |   |   |-- is_stateful_value_traits.hpp
-|   |   |   |   |-- iterator.hpp
-|   |   |   |   |-- key_nodeptr_comp.hpp
-|   |   |   |   |-- minimal_less_equal_header.hpp
-|   |   |   |   |-- minimal_pair_header.hpp
-|   |   |   |   |-- mpl.hpp
-|   |   |   |   |-- node_holder.hpp
-|   |   |   |   |-- parent_from_member.hpp
-|   |   |   |   |-- reverse_iterator.hpp
-|   |   |   |   |-- simple_disposers.hpp
-|   |   |   |   |-- size_holder.hpp
-|   |   |   |   |-- slist_iterator.hpp
-|   |   |   |   |-- slist_node.hpp
-|   |   |   |   |-- std_fwd.hpp
-|   |   |   |   |-- tree_value_compare.hpp
-|   |   |   |   |-- uncast.hpp
-|   |   |   |   `-- workaround.hpp
-|   |   |   |-- circular_slist_algorithms.hpp
-|   |   |   |-- intrusive_fwd.hpp
-|   |   |   |-- linear_slist_algorithms.hpp
-|   |   |   |-- link_mode.hpp
-|   |   |   |-- options.hpp
-|   |   |   |-- pack_options.hpp
-|   |   |   |-- pointer_rebind.hpp
-|   |   |   |-- pointer_traits.hpp
-|   |   |   |-- slist_hook.hpp
-|   |   |   `-- slist.hpp
-|   |   |-- io
-|   |   |   |-- detail
-|   |   |   |   `-- quoted_manip.hpp
-|   |   |   `-- ios_state.hpp
-|   |   |-- iterator
-|   |   |   |-- detail
-|   |   |   |   |-- any_conversion_eater.hpp
-|   |   |   |   |-- config_def.hpp
-|   |   |   |   |-- config_undef.hpp
-|   |   |   |   |-- enable_if.hpp
-|   |   |   |   |-- facade_iterator_category.hpp
-|   |   |   |   `-- minimum_category.hpp
-|   |   |   |-- advance.hpp
-|   |   |   |-- counting_iterator.hpp
-|   |   |   |-- distance.hpp
-|   |   |   |-- filter_iterator.hpp
-|   |   |   |-- function_input_iterator.hpp
-|   |   |   |-- function_output_iterator.hpp
-|   |   |   |-- indirect_iterator.hpp
-|   |   |   |-- interoperable.hpp
-|   |   |   |-- is_lvalue_iterator.hpp
-|   |   |   |-- is_readable_iterator.hpp
-|   |   |   |-- iterator_adaptor.hpp
-|   |   |   |-- iterator_archetypes.hpp
-|   |   |   |-- iterator_categories.hpp
-|   |   |   |-- iterator_concepts.hpp
-|   |   |   |-- iterator_facade.hpp
-|   |   |   |-- iterator_traits.hpp
-|   |   |   |-- minimum_category.hpp
-|   |   |   |-- new_iterator_tests.hpp
-|   |   |   |-- permutation_iterator.hpp
-|   |   |   |-- reverse_iterator.hpp
-|   |   |   |-- transform_iterator.hpp
-|   |   |   `-- zip_iterator.hpp
-|   |   |-- lexical_cast
-|   |   |   |-- detail
-|   |   |   |   |-- converter_lexical.hpp
-|   |   |   |   |-- converter_lexical_streams.hpp
-|   |   |   |   |-- converter_numeric.hpp
-|   |   |   |   |-- inf_nan.hpp
-|   |   |   |   |-- is_character.hpp
-|   |   |   |   |-- lcast_char_constants.hpp
-|   |   |   |   |-- lcast_unsigned_converters.hpp
-|   |   |   |   `-- widest_char.hpp
-|   |   |   |-- bad_lexical_cast.hpp
-|   |   |   `-- try_lexical_convert.hpp
-|   |   |-- math
-|   |   |   |-- policies
-|   |   |   |   `-- policy.hpp
-|   |   |   |-- special_functions
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- fp_traits.hpp
-|   |   |   |   |   `-- round_fwd.hpp
-|   |   |   |   |-- fpclassify.hpp
-|   |   |   |   |-- math_fwd.hpp
-|   |   |   |   `-- sign.hpp
-|   |   |   `-- tools
-|   |   |       |-- config.hpp
-|   |   |       |-- promotion.hpp
-|   |   |       |-- real_cast.hpp
-|   |   |       `-- user.hpp
-|   |   |-- move
-|   |   |   |-- detail
-|   |   |   |   |-- config_begin.hpp
-|   |   |   |   |-- config_end.hpp
-|   |   |   |   |-- fwd_macros.hpp
-|   |   |   |   |-- iterator_to_raw_pointer.hpp
-|   |   |   |   |-- iterator_traits.hpp
-|   |   |   |   |-- meta_utils_core.hpp
-|   |   |   |   |-- meta_utils.hpp
-|   |   |   |   |-- move_helpers.hpp
-|   |   |   |   |-- pointer_element.hpp
-|   |   |   |   |-- std_ns_begin.hpp
-|   |   |   |   |-- std_ns_end.hpp
-|   |   |   |   |-- to_raw_pointer.hpp
-|   |   |   |   |-- type_traits.hpp
-|   |   |   |   `-- workaround.hpp
-|   |   |   |-- adl_move_swap.hpp
-|   |   |   |-- core.hpp
-|   |   |   |-- iterator.hpp
-|   |   |   |-- traits.hpp
-|   |   |   |-- utility_core.hpp
-|   |   |   `-- utility.hpp
-|   |   |-- mp11
-|   |   |   |-- detail
-|   |   |   |   |-- config.hpp
-|   |   |   |   |-- mp_append.hpp
-|   |   |   |   |-- mp_copy_if.hpp
-|   |   |   |   |-- mp_count.hpp
-|   |   |   |   |-- mp_fold.hpp
-|   |   |   |   |-- mp_is_list.hpp
-|   |   |   |   |-- mp_list.hpp
-|   |   |   |   |-- mp_map_find.hpp
-|   |   |   |   |-- mp_min_element.hpp
-|   |   |   |   |-- mp_plus.hpp
-|   |   |   |   |-- mp_remove_if.hpp
-|   |   |   |   |-- mp_void.hpp
-|   |   |   |   `-- mp_with_index.hpp
-|   |   |   |-- algorithm.hpp
-|   |   |   |-- bind.hpp
-|   |   |   |-- function.hpp
-|   |   |   |-- integer_sequence.hpp
-|   |   |   |-- integral.hpp
-|   |   |   |-- list.hpp
-|   |   |   |-- map.hpp
-|   |   |   |-- mpl.hpp
-|   |   |   |-- set.hpp
-|   |   |   |-- tuple.hpp
-|   |   |   |-- utility.hpp
-|   |   |   `-- version.hpp
-|   |   |-- mpl
-|   |   |   |-- aux_
-|   |   |   |   |-- config
-|   |   |   |   |   |-- adl.hpp
-|   |   |   |   |   |-- arrays.hpp
-|   |   |   |   |   |-- bcc.hpp
-|   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |-- compiler.hpp
-|   |   |   |   |   |-- ctps.hpp
-|   |   |   |   |   |-- dependent_nttp.hpp
-|   |   |   |   |   |-- dmc_ambiguous_ctps.hpp
-|   |   |   |   |   |-- dtp.hpp
-|   |   |   |   |   |-- eti.hpp
-|   |   |   |   |   |-- forwarding.hpp
-|   |   |   |   |   |-- gcc.hpp
-|   |   |   |   |   |-- gpu.hpp
-|   |   |   |   |   |-- has_apply.hpp
-|   |   |   |   |   |-- has_xxx.hpp
-|   |   |   |   |   |-- integral.hpp
-|   |   |   |   |   |-- intel.hpp
-|   |   |   |   |   |-- lambda.hpp
-|   |   |   |   |   |-- msvc.hpp
-|   |   |   |   |   |-- msvc_typename.hpp
-|   |   |   |   |   |-- nttp.hpp
-|   |   |   |   |   |-- overload_resolution.hpp
-|   |   |   |   |   |-- pp_counter.hpp
-|   |   |   |   |   |-- preprocessor.hpp
-|   |   |   |   |   |-- static_constant.hpp
-|   |   |   |   |   |-- ttp.hpp
-|   |   |   |   |   |-- typeof.hpp
-|   |   |   |   |   |-- use_preprocessed.hpp
-|   |   |   |   |   `-- workaround.hpp
-|   |   |   |   |-- preprocessed
-|   |   |   |   |   |-- bcc
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- bcc551
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- bcc_pre590
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- dmc
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- gcc
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- msvc60
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- msvc70
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- mwcw
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- no_ctps
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   |-- no_ttp
-|   |   |   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |   |   |-- and.hpp
-|   |   |   |   |   |   |-- apply_fwd.hpp
-|   |   |   |   |   |   |-- apply.hpp
-|   |   |   |   |   |   |-- apply_wrap.hpp
-|   |   |   |   |   |   |-- arg.hpp
-|   |   |   |   |   |   |-- basic_bind.hpp
-|   |   |   |   |   |   |-- bind_fwd.hpp
-|   |   |   |   |   |   |-- bind.hpp
-|   |   |   |   |   |   |-- bitand.hpp
-|   |   |   |   |   |   |-- bitor.hpp
-|   |   |   |   |   |   |-- bitxor.hpp
-|   |   |   |   |   |   |-- deque.hpp
-|   |   |   |   |   |   |-- divides.hpp
-|   |   |   |   |   |   |-- equal_to.hpp
-|   |   |   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |   |   |-- greater_equal.hpp
-|   |   |   |   |   |   |-- greater.hpp
-|   |   |   |   |   |   |-- inherit.hpp
-|   |   |   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |   |   |-- less_equal.hpp
-|   |   |   |   |   |   |-- less.hpp
-|   |   |   |   |   |   |-- list_c.hpp
-|   |   |   |   |   |   |-- list.hpp
-|   |   |   |   |   |   |-- map.hpp
-|   |   |   |   |   |   |-- minus.hpp
-|   |   |   |   |   |   |-- modulus.hpp
-|   |   |   |   |   |   |-- not_equal_to.hpp
-|   |   |   |   |   |   |-- or.hpp
-|   |   |   |   |   |   |-- placeholders.hpp
-|   |   |   |   |   |   |-- plus.hpp
-|   |   |   |   |   |   |-- quote.hpp
-|   |   |   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |   |   |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |   |   |-- set_c.hpp
-|   |   |   |   |   |   |-- set.hpp
-|   |   |   |   |   |   |-- shift_left.hpp
-|   |   |   |   |   |   |-- shift_right.hpp
-|   |   |   |   |   |   |-- template_arity.hpp
-|   |   |   |   |   |   |-- times.hpp
-|   |   |   |   |   |   |-- unpack_args.hpp
-|   |   |   |   |   |   |-- vector_c.hpp
-|   |   |   |   |   |   `-- vector.hpp
-|   |   |   |   |   `-- plain
-|   |   |   |   |       |-- advance_backward.hpp
-|   |   |   |   |       |-- advance_forward.hpp
-|   |   |   |   |       |-- and.hpp
-|   |   |   |   |       |-- apply_fwd.hpp
-|   |   |   |   |       |-- apply.hpp
-|   |   |   |   |       |-- apply_wrap.hpp
-|   |   |   |   |       |-- arg.hpp
-|   |   |   |   |       |-- basic_bind.hpp
-|   |   |   |   |       |-- bind_fwd.hpp
-|   |   |   |   |       |-- bind.hpp
-|   |   |   |   |       |-- bitand.hpp
-|   |   |   |   |       |-- bitor.hpp
-|   |   |   |   |       |-- bitxor.hpp
-|   |   |   |   |       |-- deque.hpp
-|   |   |   |   |       |-- divides.hpp
-|   |   |   |   |       |-- equal_to.hpp
-|   |   |   |   |       |-- fold_impl.hpp
-|   |   |   |   |       |-- full_lambda.hpp
-|   |   |   |   |       |-- greater_equal.hpp
-|   |   |   |   |       |-- greater.hpp
-|   |   |   |   |       |-- inherit.hpp
-|   |   |   |   |       |-- iter_fold_if_impl.hpp
-|   |   |   |   |       |-- iter_fold_impl.hpp
-|   |   |   |   |       |-- lambda_no_ctps.hpp
-|   |   |   |   |       |-- less_equal.hpp
-|   |   |   |   |       |-- less.hpp
-|   |   |   |   |       |-- list_c.hpp
-|   |   |   |   |       |-- list.hpp
-|   |   |   |   |       |-- map.hpp
-|   |   |   |   |       |-- minus.hpp
-|   |   |   |   |       |-- modulus.hpp
-|   |   |   |   |       |-- not_equal_to.hpp
-|   |   |   |   |       |-- or.hpp
-|   |   |   |   |       |-- placeholders.hpp
-|   |   |   |   |       |-- plus.hpp
-|   |   |   |   |       |-- quote.hpp
-|   |   |   |   |       |-- reverse_fold_impl.hpp
-|   |   |   |   |       |-- reverse_iter_fold_impl.hpp
-|   |   |   |   |       |-- set_c.hpp
-|   |   |   |   |       |-- set.hpp
-|   |   |   |   |       |-- shift_left.hpp
-|   |   |   |   |       |-- shift_right.hpp
-|   |   |   |   |       |-- template_arity.hpp
-|   |   |   |   |       |-- times.hpp
-|   |   |   |   |       |-- unpack_args.hpp
-|   |   |   |   |       |-- vector_c.hpp
-|   |   |   |   |       `-- vector.hpp
-|   |   |   |   |-- preprocessor
-|   |   |   |   |   |-- add.hpp
-|   |   |   |   |   |-- default_params.hpp
-|   |   |   |   |   |-- def_params_tail.hpp
-|   |   |   |   |   |-- enum.hpp
-|   |   |   |   |   |-- ext_params.hpp
-|   |   |   |   |   |-- filter_params.hpp
-|   |   |   |   |   |-- is_seq.hpp
-|   |   |   |   |   |-- params.hpp
-|   |   |   |   |   |-- partial_spec_params.hpp
-|   |   |   |   |   |-- range.hpp
-|   |   |   |   |   |-- repeat.hpp
-|   |   |   |   |   |-- sub.hpp
-|   |   |   |   |   |-- token_equal.hpp
-|   |   |   |   |   `-- tuple.hpp
-|   |   |   |   |-- adl_barrier.hpp
-|   |   |   |   |-- advance_backward.hpp
-|   |   |   |   |-- advance_forward.hpp
-|   |   |   |   |-- arg_typedef.hpp
-|   |   |   |   |-- arithmetic_op.hpp
-|   |   |   |   |-- arity.hpp
-|   |   |   |   |-- arity_spec.hpp
-|   |   |   |   |-- at_impl.hpp
-|   |   |   |   |-- back_impl.hpp
-|   |   |   |   |-- begin_end_impl.hpp
-|   |   |   |   |-- clear_impl.hpp
-|   |   |   |   |-- common_name_wknd.hpp
-|   |   |   |   |-- comparison_op.hpp
-|   |   |   |   |-- contains_impl.hpp
-|   |   |   |   |-- count_args.hpp
-|   |   |   |   |-- empty_impl.hpp
-|   |   |   |   |-- erase_impl.hpp
-|   |   |   |   |-- erase_key_impl.hpp
-|   |   |   |   |-- find_if_pred.hpp
-|   |   |   |   |-- fold_impl_body.hpp
-|   |   |   |   |-- fold_impl.hpp
-|   |   |   |   |-- front_impl.hpp
-|   |   |   |   |-- full_lambda.hpp
-|   |   |   |   |-- has_apply.hpp
-|   |   |   |   |-- has_begin.hpp
-|   |   |   |   |-- has_key_impl.hpp
-|   |   |   |   |-- has_rebind.hpp
-|   |   |   |   |-- has_size.hpp
-|   |   |   |   |-- has_tag.hpp
-|   |   |   |   |-- has_type.hpp
-|   |   |   |   |-- include_preprocessed.hpp
-|   |   |   |   |-- inserter_algorithm.hpp
-|   |   |   |   |-- insert_impl.hpp
-|   |   |   |   |-- insert_range_impl.hpp
-|   |   |   |   |-- integral_wrapper.hpp
-|   |   |   |   |-- is_msvc_eti_arg.hpp
-|   |   |   |   |-- iter_apply.hpp
-|   |   |   |   |-- iter_fold_if_impl.hpp
-|   |   |   |   |-- iter_fold_impl.hpp
-|   |   |   |   |-- iter_push_front.hpp
-|   |   |   |   |-- joint_iter.hpp
-|   |   |   |   |-- lambda_arity_param.hpp
-|   |   |   |   |-- lambda_no_ctps.hpp
-|   |   |   |   |-- lambda_spec.hpp
-|   |   |   |   |-- lambda_support.hpp
-|   |   |   |   |-- largest_int.hpp
-|   |   |   |   |-- logical_op.hpp
-|   |   |   |   |-- msvc_dtw.hpp
-|   |   |   |   |-- msvc_eti_base.hpp
-|   |   |   |   |-- msvc_is_class.hpp
-|   |   |   |   |-- msvc_never_true.hpp
-|   |   |   |   |-- msvc_type.hpp
-|   |   |   |   |-- na_assert.hpp
-|   |   |   |   |-- na_fwd.hpp
-|   |   |   |   |-- na.hpp
-|   |   |   |   |-- na_spec.hpp
-|   |   |   |   |-- nested_type_wknd.hpp
-|   |   |   |   |-- nttp_decl.hpp
-|   |   |   |   |-- numeric_cast_utils.hpp
-|   |   |   |   |-- numeric_op.hpp
-|   |   |   |   |-- O1_size_impl.hpp
-|   |   |   |   |-- pop_back_impl.hpp
-|   |   |   |   |-- pop_front_impl.hpp
-|   |   |   |   |-- push_back_impl.hpp
-|   |   |   |   |-- push_front_impl.hpp
-|   |   |   |   |-- reverse_fold_impl_body.hpp
-|   |   |   |   |-- reverse_fold_impl.hpp
-|   |   |   |   |-- sequence_wrapper.hpp
-|   |   |   |   |-- size_impl.hpp
-|   |   |   |   |-- static_cast.hpp
-|   |   |   |   |-- template_arity_fwd.hpp
-|   |   |   |   |-- template_arity.hpp
-|   |   |   |   |-- traits_lambda_spec.hpp
-|   |   |   |   |-- type_wrapper.hpp
-|   |   |   |   |-- unwrap.hpp
-|   |   |   |   |-- value_wknd.hpp
-|   |   |   |   `-- yes_no.hpp
-|   |   |   |-- limits
-|   |   |   |   |-- arity.hpp
-|   |   |   |   |-- list.hpp
-|   |   |   |   |-- unrolling.hpp
-|   |   |   |   `-- vector.hpp
-|   |   |   |-- list
-|   |   |   |   |-- aux_
-|   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   `-- plain
-|   |   |   |   |   |       |-- list10_c.hpp
-|   |   |   |   |   |       |-- list10.hpp
-|   |   |   |   |   |       |-- list20_c.hpp
-|   |   |   |   |   |       |-- list20.hpp
-|   |   |   |   |   |       |-- list30_c.hpp
-|   |   |   |   |   |       |-- list30.hpp
-|   |   |   |   |   |       |-- list40_c.hpp
-|   |   |   |   |   |       |-- list40.hpp
-|   |   |   |   |   |       |-- list50_c.hpp
-|   |   |   |   |   |       `-- list50.hpp
-|   |   |   |   |   |-- begin_end.hpp
-|   |   |   |   |   |-- clear.hpp
-|   |   |   |   |   |-- empty.hpp
-|   |   |   |   |   |-- front.hpp
-|   |   |   |   |   |-- include_preprocessed.hpp
-|   |   |   |   |   |-- item.hpp
-|   |   |   |   |   |-- iterator.hpp
-|   |   |   |   |   |-- numbered_c.hpp
-|   |   |   |   |   |-- numbered.hpp
-|   |   |   |   |   |-- O1_size.hpp
-|   |   |   |   |   |-- pop_front.hpp
-|   |   |   |   |   |-- push_back.hpp
-|   |   |   |   |   |-- push_front.hpp
-|   |   |   |   |   |-- size.hpp
-|   |   |   |   |   `-- tag.hpp
-|   |   |   |   |-- list0_c.hpp
-|   |   |   |   |-- list0.hpp
-|   |   |   |   |-- list10_c.hpp
-|   |   |   |   |-- list10.hpp
-|   |   |   |   |-- list20_c.hpp
-|   |   |   |   |-- list20.hpp
-|   |   |   |   |-- list30_c.hpp
-|   |   |   |   |-- list30.hpp
-|   |   |   |   |-- list40_c.hpp
-|   |   |   |   |-- list40.hpp
-|   |   |   |   |-- list50_c.hpp
-|   |   |   |   `-- list50.hpp
-|   |   |   |-- vector
-|   |   |   |   |-- aux_
-|   |   |   |   |   |-- preprocessed
-|   |   |   |   |   |   |-- no_ctps
-|   |   |   |   |   |   |   |-- vector10_c.hpp
-|   |   |   |   |   |   |   |-- vector10.hpp
-|   |   |   |   |   |   |   |-- vector20_c.hpp
-|   |   |   |   |   |   |   |-- vector20.hpp
-|   |   |   |   |   |   |   |-- vector30_c.hpp
-|   |   |   |   |   |   |   |-- vector30.hpp
-|   |   |   |   |   |   |   |-- vector40_c.hpp
-|   |   |   |   |   |   |   |-- vector40.hpp
-|   |   |   |   |   |   |   |-- vector50_c.hpp
-|   |   |   |   |   |   |   `-- vector50.hpp
-|   |   |   |   |   |   |-- plain
-|   |   |   |   |   |   |   |-- vector10_c.hpp
-|   |   |   |   |   |   |   |-- vector10.hpp
-|   |   |   |   |   |   |   |-- vector20_c.hpp
-|   |   |   |   |   |   |   |-- vector20.hpp
-|   |   |   |   |   |   |   |-- vector30_c.hpp
-|   |   |   |   |   |   |   |-- vector30.hpp
-|   |   |   |   |   |   |   |-- vector40_c.hpp
-|   |   |   |   |   |   |   |-- vector40.hpp
-|   |   |   |   |   |   |   |-- vector50_c.hpp
-|   |   |   |   |   |   |   `-- vector50.hpp
-|   |   |   |   |   |   `-- typeof_based
-|   |   |   |   |   |       |-- vector10_c.hpp
-|   |   |   |   |   |       |-- vector10.hpp
-|   |   |   |   |   |       |-- vector20_c.hpp
-|   |   |   |   |   |       |-- vector20.hpp
-|   |   |   |   |   |       |-- vector30_c.hpp
-|   |   |   |   |   |       |-- vector30.hpp
-|   |   |   |   |   |       |-- vector40_c.hpp
-|   |   |   |   |   |       |-- vector40.hpp
-|   |   |   |   |   |       |-- vector50_c.hpp
-|   |   |   |   |   |       `-- vector50.hpp
-|   |   |   |   |   |-- at.hpp
-|   |   |   |   |   |-- back.hpp
-|   |   |   |   |   |-- begin_end.hpp
-|   |   |   |   |   |-- clear.hpp
-|   |   |   |   |   |-- empty.hpp
-|   |   |   |   |   |-- front.hpp
-|   |   |   |   |   |-- include_preprocessed.hpp
-|   |   |   |   |   |-- item.hpp
-|   |   |   |   |   |-- iterator.hpp
-|   |   |   |   |   |-- numbered_c.hpp
-|   |   |   |   |   |-- numbered.hpp
-|   |   |   |   |   |-- O1_size.hpp
-|   |   |   |   |   |-- pop_back.hpp
-|   |   |   |   |   |-- pop_front.hpp
-|   |   |   |   |   |-- push_back.hpp
-|   |   |   |   |   |-- push_front.hpp
-|   |   |   |   |   |-- size.hpp
-|   |   |   |   |   |-- tag.hpp
-|   |   |   |   |   `-- vector0.hpp
-|   |   |   |   |-- vector0_c.hpp
-|   |   |   |   |-- vector0.hpp
-|   |   |   |   |-- vector10_c.hpp
-|   |   |   |   |-- vector10.hpp
-|   |   |   |   |-- vector20_c.hpp
-|   |   |   |   |-- vector20.hpp
-|   |   |   |   |-- vector30_c.hpp
-|   |   |   |   |-- vector30.hpp
-|   |   |   |   |-- vector40_c.hpp
-|   |   |   |   |-- vector40.hpp
-|   |   |   |   |-- vector50_c.hpp
-|   |   |   |   `-- vector50.hpp
-|   |   |   |-- advance_fwd.hpp
-|   |   |   |-- advance.hpp
-|   |   |   |-- always.hpp
-|   |   |   |-- and.hpp
-|   |   |   |-- apply_fwd.hpp
-|   |   |   |-- apply.hpp
-|   |   |   |-- apply_wrap.hpp
-|   |   |   |-- arg_fwd.hpp
-|   |   |   |-- arg.hpp
-|   |   |   |-- assert.hpp
-|   |   |   |-- at_fwd.hpp
-|   |   |   |-- at.hpp
-|   |   |   |-- back_fwd.hpp
-|   |   |   |-- back.hpp
-|   |   |   |-- back_inserter.hpp
-|   |   |   |-- begin_end_fwd.hpp
-|   |   |   |-- begin_end.hpp
-|   |   |   |-- begin.hpp
-|   |   |   |-- bind_fwd.hpp
-|   |   |   |-- bind.hpp
-|   |   |   |-- bitand.hpp
-|   |   |   |-- bitxor.hpp
-|   |   |   |-- bool_fwd.hpp
-|   |   |   |-- bool.hpp
-|   |   |   |-- clear_fwd.hpp
-|   |   |   |-- clear.hpp
-|   |   |   |-- comparison.hpp
-|   |   |   |-- contains_fwd.hpp
-|   |   |   |-- contains.hpp
-|   |   |   |-- copy.hpp
-|   |   |   |-- deref.hpp
-|   |   |   |-- distance_fwd.hpp
-|   |   |   |-- distance.hpp
-|   |   |   |-- empty_base.hpp
-|   |   |   |-- empty_fwd.hpp
-|   |   |   |-- empty.hpp
-|   |   |   |-- end.hpp
-|   |   |   |-- equal_to.hpp
-|   |   |   |-- erase_fwd.hpp
-|   |   |   |-- erase.hpp
-|   |   |   |-- erase_key_fwd.hpp
-|   |   |   |-- erase_key.hpp
-|   |   |   |-- eval_if.hpp
-|   |   |   |-- find.hpp
-|   |   |   |-- find_if.hpp
-|   |   |   |-- fold.hpp
-|   |   |   |-- for_each.hpp
-|   |   |   |-- front_fwd.hpp
-|   |   |   |-- front.hpp
-|   |   |   |-- front_inserter.hpp
-|   |   |   |-- greater_equal.hpp
-|   |   |   |-- greater.hpp
-|   |   |   |-- has_key_fwd.hpp
-|   |   |   |-- has_key.hpp
-|   |   |   |-- has_xxx.hpp
-|   |   |   |-- identity.hpp
-|   |   |   |-- if.hpp
-|   |   |   |-- inherit.hpp
-|   |   |   |-- inserter.hpp
-|   |   |   |-- insert_fwd.hpp
-|   |   |   |-- insert.hpp
-|   |   |   |-- insert_range_fwd.hpp
-|   |   |   |-- insert_range.hpp
-|   |   |   |-- integral_c_fwd.hpp
-|   |   |   |-- integral_c.hpp
-|   |   |   |-- integral_c_tag.hpp
-|   |   |   |-- int_fwd.hpp
-|   |   |   |-- int.hpp
-|   |   |   |-- is_placeholder.hpp
-|   |   |   |-- is_sequence.hpp
-|   |   |   |-- iterator_category.hpp
-|   |   |   |-- iterator_range.hpp
-|   |   |   |-- iterator_tags.hpp
-|   |   |   |-- iter_fold.hpp
-|   |   |   |-- iter_fold_if.hpp
-|   |   |   |-- joint_view.hpp
-|   |   |   |-- lambda_fwd.hpp
-|   |   |   |-- lambda.hpp
-|   |   |   |-- less_equal.hpp
-|   |   |   |-- less.hpp
-|   |   |   |-- list.hpp
-|   |   |   |-- logical.hpp
-|   |   |   |-- long_fwd.hpp
-|   |   |   |-- long.hpp
-|   |   |   |-- min_max.hpp
-|   |   |   |-- minus.hpp
-|   |   |   |-- multiplies.hpp
-|   |   |   |-- negate.hpp
-|   |   |   |-- next.hpp
-|   |   |   |-- next_prior.hpp
-|   |   |   |-- not_equal_to.hpp
-|   |   |   |-- not.hpp
-|   |   |   |-- numeric_cast.hpp
-|   |   |   |-- O1_size_fwd.hpp
-|   |   |   |-- O1_size.hpp
-|   |   |   |-- or.hpp
-|   |   |   |-- pair.hpp
-|   |   |   |-- pair_view.hpp
-|   |   |   |-- placeholders.hpp
-|   |   |   |-- plus.hpp
-|   |   |   |-- pop_back_fwd.hpp
-|   |   |   |-- pop_back.hpp
-|   |   |   |-- pop_front_fwd.hpp
-|   |   |   |-- pop_front.hpp
-|   |   |   |-- prior.hpp
-|   |   |   |-- protect.hpp
-|   |   |   |-- push_back_fwd.hpp
-|   |   |   |-- push_back.hpp
-|   |   |   |-- push_front_fwd.hpp
-|   |   |   |-- push_front.hpp
-|   |   |   |-- quote.hpp
-|   |   |   |-- remove.hpp
-|   |   |   |-- remove_if.hpp
-|   |   |   |-- reverse_fold.hpp
-|   |   |   |-- reverse.hpp
-|   |   |   |-- same_as.hpp
-|   |   |   |-- sequence_tag_fwd.hpp
-|   |   |   |-- sequence_tag.hpp
-|   |   |   |-- size_fwd.hpp
-|   |   |   |-- size.hpp
-|   |   |   |-- size_t_fwd.hpp
-|   |   |   |-- size_t.hpp
-|   |   |   |-- tag.hpp
-|   |   |   |-- times.hpp
-|   |   |   |-- transform.hpp
-|   |   |   |-- vector.hpp
-|   |   |   |-- void_fwd.hpp
-|   |   |   `-- void.hpp
-|   |   |-- numeric
-|   |   |   `-- conversion
-|   |   |       |-- detail
-|   |   |       |   |-- preprocessed
-|   |   |       |   |   |-- numeric_cast_traits_common.hpp
-|   |   |       |   |   `-- numeric_cast_traits_long_long.hpp
-|   |   |       |   |-- bounds.hpp
-|   |   |       |   |-- conversion_traits.hpp
-|   |   |       |   |-- converter.hpp
-|   |   |       |   |-- int_float_mixture.hpp
-|   |   |       |   |-- is_subranged.hpp
-|   |   |       |   |-- meta.hpp
-|   |   |       |   |-- numeric_cast_traits.hpp
-|   |   |       |   |-- old_numeric_cast.hpp
-|   |   |       |   |-- sign_mixture.hpp
-|   |   |       |   `-- udt_builtin_mixture.hpp
-|   |   |       |-- bounds.hpp
-|   |   |       |-- cast.hpp
-|   |   |       |-- conversion_traits.hpp
-|   |   |       |-- converter.hpp
-|   |   |       |-- converter_policies.hpp
-|   |   |       |-- int_float_mixture_enum.hpp
-|   |   |       |-- numeric_cast_traits.hpp
-|   |   |       |-- sign_mixture_enum.hpp
-|   |   |       `-- udt_builtin_mixture_enum.hpp
-|   |   |-- optional
-|   |   |   |-- detail
-|   |   |   |   |-- experimental_traits.hpp
-|   |   |   |   |-- old_optional_implementation.hpp
-|   |   |   |   |-- optional_aligned_storage.hpp
-|   |   |   |   |-- optional_config.hpp
-|   |   |   |   |-- optional_factory_support.hpp
-|   |   |   |   |-- optional_reference_spec.hpp
-|   |   |   |   |-- optional_relops.hpp
-|   |   |   |   |-- optional_swap.hpp
-|   |   |   |   `-- optional_trivially_copyable_base.hpp
-|   |   |   |-- bad_optional_access.hpp
-|   |   |   |-- optional_fwd.hpp
-|   |   |   |-- optional.hpp
-|   |   |   `-- optional_io.hpp
-|   |   |-- pending
-|   |   |   `-- iterator_tests.hpp
-|   |   |-- predef
-|   |   |   |-- architecture
-|   |   |   |   |-- x86
-|   |   |   |   |   |-- 32.h
-|   |   |   |   |   `-- 64.h
-|   |   |   |   |-- alpha.h
-|   |   |   |   |-- arm.h
-|   |   |   |   |-- blackfin.h
-|   |   |   |   |-- convex.h
-|   |   |   |   |-- ia64.h
-|   |   |   |   |-- m68k.h
-|   |   |   |   |-- mips.h
-|   |   |   |   |-- parisc.h
-|   |   |   |   |-- ppc.h
-|   |   |   |   |-- ptx.h
-|   |   |   |   |-- pyramid.h
-|   |   |   |   |-- rs6k.h
-|   |   |   |   |-- sparc.h
-|   |   |   |   |-- superh.h
-|   |   |   |   |-- sys370.h
-|   |   |   |   |-- sys390.h
-|   |   |   |   |-- x86.h
-|   |   |   |   `-- z.h
-|   |   |   |-- compiler
-|   |   |   |   |-- borland.h
-|   |   |   |   |-- clang.h
-|   |   |   |   |-- comeau.h
-|   |   |   |   |-- compaq.h
-|   |   |   |   |-- diab.h
-|   |   |   |   |-- digitalmars.h
-|   |   |   |   |-- dignus.h
-|   |   |   |   |-- edg.h
-|   |   |   |   |-- ekopath.h
-|   |   |   |   |-- gcc.h
-|   |   |   |   |-- gcc_xml.h
-|   |   |   |   |-- greenhills.h
-|   |   |   |   |-- hp_acc.h
-|   |   |   |   |-- iar.h
-|   |   |   |   |-- ibm.h
-|   |   |   |   |-- intel.h
-|   |   |   |   |-- kai.h
-|   |   |   |   |-- llvm.h
-|   |   |   |   |-- metaware.h
-|   |   |   |   |-- metrowerks.h
-|   |   |   |   |-- microtec.h
-|   |   |   |   |-- mpw.h
-|   |   |   |   |-- nvcc.h
-|   |   |   |   |-- palm.h
-|   |   |   |   |-- pgi.h
-|   |   |   |   |-- sgi_mipspro.h
-|   |   |   |   |-- sunpro.h
-|   |   |   |   |-- tendra.h
-|   |   |   |   |-- visualc.h
-|   |   |   |   `-- watcom.h
-|   |   |   |-- detail
-|   |   |   |   |-- _cassert.h
-|   |   |   |   |-- comp_detected.h
-|   |   |   |   |-- _exception.h
-|   |   |   |   |-- os_detected.h
-|   |   |   |   |-- platform_detected.h
-|   |   |   |   `-- test.h
-|   |   |   |-- hardware
-|   |   |   |   |-- simd
-|   |   |   |   |   |-- arm
-|   |   |   |   |   |   `-- versions.h
-|   |   |   |   |   |-- ppc
-|   |   |   |   |   |   `-- versions.h
-|   |   |   |   |   |-- x86
-|   |   |   |   |   |   `-- versions.h
-|   |   |   |   |   |-- x86_amd
-|   |   |   |   |   |   `-- versions.h
-|   |   |   |   |   |-- arm.h
-|   |   |   |   |   |-- ppc.h
-|   |   |   |   |   |-- x86_amd.h
-|   |   |   |   |   `-- x86.h
-|   |   |   |   `-- simd.h
-|   |   |   |-- language
-|   |   |   |   |-- cuda.h
-|   |   |   |   |-- objc.h
-|   |   |   |   |-- stdc.h
-|   |   |   |   `-- stdcpp.h
-|   |   |   |-- library
-|   |   |   |   |-- c
-|   |   |   |   |   |-- cloudabi.h
-|   |   |   |   |   |-- gnu.h
-|   |   |   |   |   |-- _prefix.h
-|   |   |   |   |   |-- uc.h
-|   |   |   |   |   |-- vms.h
-|   |   |   |   |   `-- zos.h
-|   |   |   |   |-- std
-|   |   |   |   |   |-- cxx.h
-|   |   |   |   |   |-- dinkumware.h
-|   |   |   |   |   |-- libcomo.h
-|   |   |   |   |   |-- modena.h
-|   |   |   |   |   |-- msl.h
-|   |   |   |   |   |-- _prefix.h
-|   |   |   |   |   |-- roguewave.h
-|   |   |   |   |   |-- sgi.h
-|   |   |   |   |   |-- stdcpp3.h
-|   |   |   |   |   |-- stlport.h
-|   |   |   |   |   `-- vacpp.h
-|   |   |   |   |-- c.h
-|   |   |   |   `-- std.h
-|   |   |   |-- os
-|   |   |   |   |-- bsd
-|   |   |   |   |   |-- bsdi.h
-|   |   |   |   |   |-- dragonfly.h
-|   |   |   |   |   |-- free.h
-|   |   |   |   |   |-- net.h
-|   |   |   |   |   `-- open.h
-|   |   |   |   |-- aix.h
-|   |   |   |   |-- amigaos.h
-|   |   |   |   |-- android.h
-|   |   |   |   |-- beos.h
-|   |   |   |   |-- bsd.h
-|   |   |   |   |-- cygwin.h
-|   |   |   |   |-- haiku.h
-|   |   |   |   |-- hpux.h
-|   |   |   |   |-- ios.h
-|   |   |   |   |-- irix.h
-|   |   |   |   |-- linux.h
-|   |   |   |   |-- macos.h
-|   |   |   |   |-- os400.h
-|   |   |   |   |-- qnxnto.h
-|   |   |   |   |-- solaris.h
-|   |   |   |   |-- unix.h
-|   |   |   |   |-- vms.h
-|   |   |   |   `-- windows.h
-|   |   |   |-- other
-|   |   |   |   `-- endian.h
-|   |   |   |-- platform
-|   |   |   |   |-- android.h
-|   |   |   |   |-- cloudabi.h
-|   |   |   |   |-- ios.h
-|   |   |   |   |-- mingw32.h
-|   |   |   |   |-- mingw64.h
-|   |   |   |   |-- mingw.h
-|   |   |   |   |-- windows_desktop.h
-|   |   |   |   |-- windows_phone.h
-|   |   |   |   |-- windows_runtime.h
-|   |   |   |   |-- windows_server.h
-|   |   |   |   |-- windows_store.h
-|   |   |   |   |-- windows_system.h
-|   |   |   |   `-- windows_uwp.h
-|   |   |   |-- architecture.h
-|   |   |   |-- compiler.h
-|   |   |   |-- hardware.h
-|   |   |   |-- language.h
-|   |   |   |-- library.h
-|   |   |   |-- make.h
-|   |   |   |-- os.h
-|   |   |   |-- other.h
-|   |   |   |-- platform.h
-|   |   |   |-- version.h
-|   |   |   `-- version_number.h
-|   |   |-- preprocessor
-|   |   |   |-- arithmetic
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- div_base.hpp
-|   |   |   |   |-- add.hpp
-|   |   |   |   |-- dec.hpp
-|   |   |   |   |-- inc.hpp
-|   |   |   |   |-- mod.hpp
-|   |   |   |   `-- sub.hpp
-|   |   |   |-- array
-|   |   |   |   |-- data.hpp
-|   |   |   |   |-- elem.hpp
-|   |   |   |   `-- size.hpp
-|   |   |   |-- comparison
-|   |   |   |   |-- equal.hpp
-|   |   |   |   |-- less_equal.hpp
-|   |   |   |   |-- less.hpp
-|   |   |   |   `-- not_equal.hpp
-|   |   |   |-- config
-|   |   |   |   `-- config.hpp
-|   |   |   |-- control
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- dmc
-|   |   |   |   |   |   `-- while.hpp
-|   |   |   |   |   |-- edg
-|   |   |   |   |   |   `-- while.hpp
-|   |   |   |   |   |-- msvc
-|   |   |   |   |   |   `-- while.hpp
-|   |   |   |   |   `-- while.hpp
-|   |   |   |   |-- deduce_d.hpp
-|   |   |   |   |-- expr_if.hpp
-|   |   |   |   |-- expr_iif.hpp
-|   |   |   |   |-- if.hpp
-|   |   |   |   |-- iif.hpp
-|   |   |   |   `-- while.hpp
-|   |   |   |-- debug
-|   |   |   |   `-- error.hpp
-|   |   |   |-- detail
-|   |   |   |   |-- dmc
-|   |   |   |   |   `-- auto_rec.hpp
-|   |   |   |   |-- auto_rec.hpp
-|   |   |   |   |-- check.hpp
-|   |   |   |   |-- is_binary.hpp
-|   |   |   |   |-- is_unary.hpp
-|   |   |   |   `-- split.hpp
-|   |   |   |-- facilities
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- is_empty.hpp
-|   |   |   |   |-- empty.hpp
-|   |   |   |   |-- expand.hpp
-|   |   |   |   |-- identity.hpp
-|   |   |   |   |-- intercept.hpp
-|   |   |   |   |-- is_1.hpp
-|   |   |   |   |-- is_empty.hpp
-|   |   |   |   |-- is_empty_variadic.hpp
-|   |   |   |   `-- overload.hpp
-|   |   |   |-- iteration
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- bounds
-|   |   |   |   |   |   |-- lower1.hpp
-|   |   |   |   |   |   |-- lower2.hpp
-|   |   |   |   |   |   |-- lower3.hpp
-|   |   |   |   |   |   |-- lower4.hpp
-|   |   |   |   |   |   |-- lower5.hpp
-|   |   |   |   |   |   |-- upper1.hpp
-|   |   |   |   |   |   |-- upper2.hpp
-|   |   |   |   |   |   |-- upper3.hpp
-|   |   |   |   |   |   |-- upper4.hpp
-|   |   |   |   |   |   `-- upper5.hpp
-|   |   |   |   |   |-- iter
-|   |   |   |   |   |   |-- forward1.hpp
-|   |   |   |   |   |   |-- forward2.hpp
-|   |   |   |   |   |   |-- forward3.hpp
-|   |   |   |   |   |   |-- forward4.hpp
-|   |   |   |   |   |   |-- forward5.hpp
-|   |   |   |   |   |   |-- reverse1.hpp
-|   |   |   |   |   |   |-- reverse2.hpp
-|   |   |   |   |   |   |-- reverse3.hpp
-|   |   |   |   |   |   |-- reverse4.hpp
-|   |   |   |   |   |   `-- reverse5.hpp
-|   |   |   |   |   |-- finish.hpp
-|   |   |   |   |   |-- local.hpp
-|   |   |   |   |   |-- rlocal.hpp
-|   |   |   |   |   |-- self.hpp
-|   |   |   |   |   `-- start.hpp
-|   |   |   |   |-- iterate.hpp
-|   |   |   |   |-- local.hpp
-|   |   |   |   `-- self.hpp
-|   |   |   |-- list
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- dmc
-|   |   |   |   |   |   `-- fold_left.hpp
-|   |   |   |   |   |-- edg
-|   |   |   |   |   |   |-- fold_left.hpp
-|   |   |   |   |   |   `-- fold_right.hpp
-|   |   |   |   |   |-- fold_left.hpp
-|   |   |   |   |   `-- fold_right.hpp
-|   |   |   |   |-- adt.hpp
-|   |   |   |   |-- fold_left.hpp
-|   |   |   |   |-- fold_right.hpp
-|   |   |   |   |-- for_each_i.hpp
-|   |   |   |   `-- reverse.hpp
-|   |   |   |-- logical
-|   |   |   |   |-- and.hpp
-|   |   |   |   |-- bitand.hpp
-|   |   |   |   |-- bitor.hpp
-|   |   |   |   |-- bool.hpp
-|   |   |   |   |-- compl.hpp
-|   |   |   |   |-- not.hpp
-|   |   |   |   `-- or.hpp
-|   |   |   |-- punctuation
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- is_begin_parens.hpp
-|   |   |   |   |-- comma.hpp
-|   |   |   |   |-- comma_if.hpp
-|   |   |   |   |-- is_begin_parens.hpp
-|   |   |   |   `-- paren.hpp
-|   |   |   |-- repetition
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- dmc
-|   |   |   |   |   |   `-- for.hpp
-|   |   |   |   |   |-- edg
-|   |   |   |   |   |   `-- for.hpp
-|   |   |   |   |   |-- msvc
-|   |   |   |   |   |   `-- for.hpp
-|   |   |   |   |   `-- for.hpp
-|   |   |   |   |-- enum_binary_params.hpp
-|   |   |   |   |-- enum.hpp
-|   |   |   |   |-- enum_params.hpp
-|   |   |   |   |-- enum_params_with_a_default.hpp
-|   |   |   |   |-- enum_shifted.hpp
-|   |   |   |   |-- enum_shifted_params.hpp
-|   |   |   |   |-- enum_trailing.hpp
-|   |   |   |   |-- enum_trailing_params.hpp
-|   |   |   |   |-- for.hpp
-|   |   |   |   |-- repeat_from_to.hpp
-|   |   |   |   `-- repeat.hpp
-|   |   |   |-- seq
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- is_empty.hpp
-|   |   |   |   |   `-- split.hpp
-|   |   |   |   |-- cat.hpp
-|   |   |   |   |-- elem.hpp
-|   |   |   |   |-- enum.hpp
-|   |   |   |   |-- first_n.hpp
-|   |   |   |   |-- fold_left.hpp
-|   |   |   |   |-- for_each.hpp
-|   |   |   |   |-- for_each_i.hpp
-|   |   |   |   |-- push_front.hpp
-|   |   |   |   |-- rest_n.hpp
-|   |   |   |   |-- seq.hpp
-|   |   |   |   |-- size.hpp
-|   |   |   |   |-- subseq.hpp
-|   |   |   |   |-- to_tuple.hpp
-|   |   |   |   `-- transform.hpp
-|   |   |   |-- slot
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- counter.hpp
-|   |   |   |   |   |-- def.hpp
-|   |   |   |   |   |-- shared.hpp
-|   |   |   |   |   |-- slot1.hpp
-|   |   |   |   |   |-- slot2.hpp
-|   |   |   |   |   |-- slot3.hpp
-|   |   |   |   |   |-- slot4.hpp
-|   |   |   |   |   `-- slot5.hpp
-|   |   |   |   `-- slot.hpp
-|   |   |   |-- tuple
-|   |   |   |   |-- detail
-|   |   |   |   |   `-- is_single_return.hpp
-|   |   |   |   |-- eat.hpp
-|   |   |   |   |-- elem.hpp
-|   |   |   |   |-- rem.hpp
-|   |   |   |   |-- size.hpp
-|   |   |   |   |-- to_list.hpp
-|   |   |   |   `-- to_seq.hpp
-|   |   |   |-- variadic
-|   |   |   |   |-- elem.hpp
-|   |   |   |   |-- size.hpp
-|   |   |   |   `-- to_seq.hpp
-|   |   |   |-- cat.hpp
-|   |   |   |-- comma_if.hpp
-|   |   |   |-- dec.hpp
-|   |   |   |-- empty.hpp
-|   |   |   |-- enum.hpp
-|   |   |   |-- enum_params.hpp
-|   |   |   |-- enum_params_with_a_default.hpp
-|   |   |   |-- enum_shifted_params.hpp
-|   |   |   |-- expr_if.hpp
-|   |   |   |-- identity.hpp
-|   |   |   |-- if.hpp
-|   |   |   |-- inc.hpp
-|   |   |   |-- iterate.hpp
-|   |   |   |-- repeat_from_to.hpp
-|   |   |   |-- repeat.hpp
-|   |   |   `-- stringize.hpp
-|   |   |-- program_options
-|   |   |   |-- detail
-|   |   |   |   |-- cmdline.hpp
-|   |   |   |   |-- config_file.hpp
-|   |   |   |   |-- convert.hpp
-|   |   |   |   |-- parsers.hpp
-|   |   |   |   |-- utf8_codecvt_facet.hpp
-|   |   |   |   `-- value_semantic.hpp
-|   |   |   |-- cmdline.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- environment_iterator.hpp
-|   |   |   |-- eof_iterator.hpp
-|   |   |   |-- errors.hpp
-|   |   |   |-- option.hpp
-|   |   |   |-- options_description.hpp
-|   |   |   |-- parsers.hpp
-|   |   |   |-- positional_options.hpp
-|   |   |   |-- value_semantic.hpp
-|   |   |   |-- variables_map.hpp
-|   |   |   `-- version.hpp
-|   |   |-- range
-|   |   |   |-- algorithm
-|   |   |   |   `-- equal.hpp
-|   |   |   |-- detail
-|   |   |   |   |-- as_literal.hpp
-|   |   |   |   |-- begin.hpp
-|   |   |   |   |-- common.hpp
-|   |   |   |   |-- detail_str.hpp
-|   |   |   |   |-- end.hpp
-|   |   |   |   |-- extract_optional_type.hpp
-|   |   |   |   |-- has_member_size.hpp
-|   |   |   |   |-- implementation_help.hpp
-|   |   |   |   |-- misc_concept.hpp
-|   |   |   |   |-- msvc_has_iterator_workaround.hpp
-|   |   |   |   |-- remove_extent.hpp
-|   |   |   |   |-- safe_bool.hpp
-|   |   |   |   |-- sfinae.hpp
-|   |   |   |   |-- size_type.hpp
-|   |   |   |   |-- str_types.hpp
-|   |   |   |   `-- value_type.hpp
-|   |   |   |-- as_literal.hpp
-|   |   |   |-- begin.hpp
-|   |   |   |-- concepts.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- const_iterator.hpp
-|   |   |   |-- difference_type.hpp
-|   |   |   |-- distance.hpp
-|   |   |   |-- empty.hpp
-|   |   |   |-- end.hpp
-|   |   |   |-- functions.hpp
-|   |   |   |-- has_range_iterator.hpp
-|   |   |   |-- iterator.hpp
-|   |   |   |-- iterator_range_core.hpp
-|   |   |   |-- iterator_range.hpp
-|   |   |   |-- iterator_range_io.hpp
-|   |   |   |-- mutable_iterator.hpp
-|   |   |   |-- range_fwd.hpp
-|   |   |   |-- rbegin.hpp
-|   |   |   |-- rend.hpp
-|   |   |   |-- reverse_iterator.hpp
-|   |   |   |-- size.hpp
-|   |   |   |-- size_type.hpp
-|   |   |   `-- value_type.hpp
-|   |   |-- ratio
-|   |   |   |-- detail
-|   |   |   |   |-- mpl
-|   |   |   |   |   |-- abs.hpp
-|   |   |   |   |   |-- gcd.hpp
-|   |   |   |   |   |-- lcm.hpp
-|   |   |   |   |   `-- sign.hpp
-|   |   |   |   `-- overflow_helpers.hpp
-|   |   |   |-- mpl
-|   |   |   |   `-- rational_c_tag.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- ratio_fwd.hpp
-|   |   |   `-- ratio.hpp
-|   |   |-- smart_ptr
-|   |   |   |-- detail
-|   |   |   |   |-- atomic_count_gcc.hpp
-|   |   |   |   |-- atomic_count_gcc_x86.hpp
-|   |   |   |   |-- atomic_count.hpp
-|   |   |   |   |-- atomic_count_nt.hpp
-|   |   |   |   |-- atomic_count_pt.hpp
-|   |   |   |   |-- atomic_count_spin.hpp
-|   |   |   |   |-- atomic_count_std_atomic.hpp
-|   |   |   |   |-- atomic_count_sync.hpp
-|   |   |   |   |-- atomic_count_win32.hpp
-|   |   |   |   |-- lightweight_mutex.hpp
-|   |   |   |   |-- local_counted_base.hpp
-|   |   |   |   |-- local_sp_deleter.hpp
-|   |   |   |   |-- lwm_nop.hpp
-|   |   |   |   |-- lwm_pthreads.hpp
-|   |   |   |   |-- lwm_win32_cs.hpp
-|   |   |   |   |-- operator_bool.hpp
-|   |   |   |   |-- quick_allocator.hpp
-|   |   |   |   |-- shared_count.hpp
-|   |   |   |   |-- sp_convertible.hpp
-|   |   |   |   |-- sp_counted_base_acc_ia64.hpp
-|   |   |   |   |-- sp_counted_base_aix.hpp
-|   |   |   |   |-- sp_counted_base_clang.hpp
-|   |   |   |   |-- sp_counted_base_cw_ppc.hpp
-|   |   |   |   |-- sp_counted_base_gcc_ia64.hpp
-|   |   |   |   |-- sp_counted_base_gcc_mips.hpp
-|   |   |   |   |-- sp_counted_base_gcc_ppc.hpp
-|   |   |   |   |-- sp_counted_base_gcc_sparc.hpp
-|   |   |   |   |-- sp_counted_base_gcc_x86.hpp
-|   |   |   |   |-- sp_counted_base.hpp
-|   |   |   |   |-- sp_counted_base_nt.hpp
-|   |   |   |   |-- sp_counted_base_pt.hpp
-|   |   |   |   |-- sp_counted_base_snc_ps3.hpp
-|   |   |   |   |-- sp_counted_base_spin.hpp
-|   |   |   |   |-- sp_counted_base_std_atomic.hpp
-|   |   |   |   |-- sp_counted_base_sync.hpp
-|   |   |   |   |-- sp_counted_base_vacpp_ppc.hpp
-|   |   |   |   |-- sp_counted_base_w32.hpp
-|   |   |   |   |-- sp_counted_impl.hpp
-|   |   |   |   |-- sp_disable_deprecated.hpp
-|   |   |   |   |-- sp_forward.hpp
-|   |   |   |   |-- sp_has_sync.hpp
-|   |   |   |   |-- spinlock_gcc_arm.hpp
-|   |   |   |   |-- spinlock.hpp
-|   |   |   |   |-- spinlock_nt.hpp
-|   |   |   |   |-- spinlock_pool.hpp
-|   |   |   |   |-- spinlock_pt.hpp
-|   |   |   |   |-- spinlock_std_atomic.hpp
-|   |   |   |   |-- spinlock_sync.hpp
-|   |   |   |   |-- spinlock_w32.hpp
-|   |   |   |   |-- sp_interlocked.hpp
-|   |   |   |   |-- sp_noexcept.hpp
-|   |   |   |   |-- sp_nullptr_t.hpp
-|   |   |   |   `-- yield_k.hpp
-|   |   |   |-- allocate_shared_array.hpp
-|   |   |   |-- bad_weak_ptr.hpp
-|   |   |   |-- intrusive_ptr.hpp
-|   |   |   |-- intrusive_ref_counter.hpp
-|   |   |   |-- make_shared_array.hpp
-|   |   |   |-- make_shared.hpp
-|   |   |   |-- make_shared_object.hpp
-|   |   |   |-- scoped_array.hpp
-|   |   |   |-- scoped_ptr.hpp
-|   |   |   `-- shared_ptr.hpp
-|   |   |-- system
-|   |   |   |-- detail
-|   |   |   |   |-- config.hpp
-|   |   |   |   |-- generic_category.hpp
-|   |   |   |   |-- std_interoperability.hpp
-|   |   |   |   |-- system_category_posix.hpp
-|   |   |   |   `-- system_category_win32.hpp
-|   |   |   |-- api_config.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- error_code.hpp
-|   |   |   `-- system_error.hpp
-|   |   |-- test
-|   |   |   |-- detail
-|   |   |   |   |-- config.hpp
-|   |   |   |   |-- enable_warnings.hpp
-|   |   |   |   |-- fwd_decl.hpp
-|   |   |   |   |-- global_typedef.hpp
-|   |   |   |   |-- log_level.hpp
-|   |   |   |   |-- pp_variadic.hpp
-|   |   |   |   |-- suppress_warnings.hpp
-|   |   |   |   `-- throw_exception.hpp
-|   |   |   |-- impl
-|   |   |   |   |-- compiler_log_formatter.ipp
-|   |   |   |   |-- cpp_main.ipp
-|   |   |   |   |-- debug.ipp
-|   |   |   |   |-- decorator.ipp
-|   |   |   |   |-- execution_monitor.ipp
-|   |   |   |   |-- framework.ipp
-|   |   |   |   |-- junit_log_formatter.ipp
-|   |   |   |   |-- plain_report_formatter.ipp
-|   |   |   |   |-- progress_monitor.ipp
-|   |   |   |   |-- results_collector.ipp
-|   |   |   |   |-- results_reporter.ipp
-|   |   |   |   |-- test_framework_init_observer.ipp
-|   |   |   |   |-- test_main.ipp
-|   |   |   |   |-- test_tools.ipp
-|   |   |   |   |-- test_tree.ipp
-|   |   |   |   |-- unit_test_log.ipp
-|   |   |   |   |-- unit_test_main.ipp
-|   |   |   |   |-- unit_test_monitor.ipp
-|   |   |   |   |-- unit_test_parameters.ipp
-|   |   |   |   |-- xml_log_formatter.ipp
-|   |   |   |   `-- xml_report_formatter.ipp
-|   |   |   |-- output
-|   |   |   |   |-- compiler_log_formatter.hpp
-|   |   |   |   |-- junit_log_formatter.hpp
-|   |   |   |   |-- plain_report_formatter.hpp
-|   |   |   |   |-- xml_log_formatter.hpp
-|   |   |   |   `-- xml_report_formatter.hpp
-|   |   |   |-- tools
-|   |   |   |   |-- detail
-|   |   |   |   |   |-- bitwise_manip.hpp
-|   |   |   |   |   |-- expression_holder.hpp
-|   |   |   |   |   |-- fwd.hpp
-|   |   |   |   |   |-- indirections.hpp
-|   |   |   |   |   |-- it_pair.hpp
-|   |   |   |   |   |-- lexicographic_manip.hpp
-|   |   |   |   |   |-- per_element_manip.hpp
-|   |   |   |   |   |-- print_helper.hpp
-|   |   |   |   |   `-- tolerance_manip.hpp
-|   |   |   |   |-- old
-|   |   |   |   |   |-- impl.hpp
-|   |   |   |   |   `-- interface.hpp
-|   |   |   |   |-- assertion.hpp
-|   |   |   |   |-- assertion_result.hpp
-|   |   |   |   |-- collection_comparison_op.hpp
-|   |   |   |   |-- context.hpp
-|   |   |   |   |-- cstring_comparison_op.hpp
-|   |   |   |   |-- floating_point_comparison.hpp
-|   |   |   |   |-- fpc_op.hpp
-|   |   |   |   |-- fpc_tolerance.hpp
-|   |   |   |   |-- interface.hpp
-|   |   |   |   `-- output_test_stream.hpp
-|   |   |   |-- tree
-|   |   |   |   |-- auto_registration.hpp
-|   |   |   |   |-- decorator.hpp
-|   |   |   |   |-- fixture.hpp
-|   |   |   |   |-- global_fixture.hpp
-|   |   |   |   |-- observer.hpp
-|   |   |   |   |-- test_case_counter.hpp
-|   |   |   |   |-- test_case_template.hpp
-|   |   |   |   |-- test_unit.hpp
-|   |   |   |   |-- traverse.hpp
-|   |   |   |   `-- visitor.hpp
-|   |   |   |-- utils
-|   |   |   |   |-- basic_cstring
-|   |   |   |   |   |-- basic_cstring_fwd.hpp
-|   |   |   |   |   |-- basic_cstring.hpp
-|   |   |   |   |   |-- bcs_char_traits.hpp
-|   |   |   |   |   |-- compare.hpp
-|   |   |   |   |   `-- io.hpp
-|   |   |   |   |-- iterator
-|   |   |   |   |   |-- input_iterator_facade.hpp
-|   |   |   |   |   `-- token_iterator.hpp
-|   |   |   |   |-- runtime
-|   |   |   |   |   |-- cla
-|   |   |   |   |   |   |-- argv_traverser.hpp
-|   |   |   |   |   |   `-- parser.hpp
-|   |   |   |   |   |-- env
-|   |   |   |   |   |   `-- fetch.hpp
-|   |   |   |   |   |-- argument_factory.hpp
-|   |   |   |   |   |-- argument.hpp
-|   |   |   |   |   |-- errors.hpp
-|   |   |   |   |   |-- finalize.hpp
-|   |   |   |   |   |-- fwd.hpp
-|   |   |   |   |   |-- modifier.hpp
-|   |   |   |   |   `-- parameter.hpp
-|   |   |   |   |-- algorithm.hpp
-|   |   |   |   |-- assign_op.hpp
-|   |   |   |   |-- class_properties.hpp
-|   |   |   |   |-- custom_manip.hpp
-|   |   |   |   |-- foreach.hpp
-|   |   |   |   |-- is_cstring.hpp
-|   |   |   |   |-- is_forward_iterable.hpp
-|   |   |   |   |-- lazy_ostream.hpp
-|   |   |   |   |-- named_params.hpp
-|   |   |   |   |-- rtti.hpp
-|   |   |   |   |-- setcolor.hpp
-|   |   |   |   |-- string_cast.hpp
-|   |   |   |   |-- timer.hpp
-|   |   |   |   |-- wrap_stringstream.hpp
-|   |   |   |   `-- xml_printer.hpp
-|   |   |   |-- debug_config.hpp
-|   |   |   |-- debug.hpp
-|   |   |   |-- execution_monitor.hpp
-|   |   |   |-- framework.hpp
-|   |   |   |-- minimal.hpp
-|   |   |   |-- progress_monitor.hpp
-|   |   |   |-- results_collector.hpp
-|   |   |   |-- results_reporter.hpp
-|   |   |   |-- test_framework_init_observer.hpp
-|   |   |   |-- test_tools.hpp
-|   |   |   |-- unit_test_log_formatter.hpp
-|   |   |   |-- unit_test_log.hpp
-|   |   |   |-- unit_test_monitor.hpp
-|   |   |   |-- unit_test_parameters.hpp
-|   |   |   `-- unit_test_suite.hpp
-|   |   |-- timer
-|   |   |   |-- config.hpp
-|   |   |   `-- timer.hpp
-|   |   |-- tuple
-|   |   |   |-- detail
-|   |   |   |   `-- tuple_basic.hpp
-|   |   |   `-- tuple.hpp
-|   |   |-- type_index
-|   |   |   |-- detail
-|   |   |   |   |-- compile_time_type_info.hpp
-|   |   |   |   |-- ctti_register_class.hpp
-|   |   |   |   `-- stl_register_class.hpp
-|   |   |   |-- ctti_type_index.hpp
-|   |   |   |-- stl_type_index.hpp
-|   |   |   `-- type_index_facade.hpp
-|   |   |-- typeof
-|   |   |   |-- dmc
-|   |   |   |   `-- typeof_impl.hpp
-|   |   |   |-- msvc
-|   |   |   |   `-- typeof_impl.hpp
-|   |   |   |-- constant.hpp
-|   |   |   |-- decltype.hpp
-|   |   |   |-- encode_decode.hpp
-|   |   |   |-- encode_decode_params.hpp
-|   |   |   |-- integral_template_param.hpp
-|   |   |   |-- int_encoding.hpp
-|   |   |   |-- message.hpp
-|   |   |   |-- modifiers.hpp
-|   |   |   |-- native.hpp
-|   |   |   |-- pointers_data_members.hpp
-|   |   |   |-- register_functions.hpp
-|   |   |   |-- register_functions_iterate.hpp
-|   |   |   |-- register_fundamental.hpp
-|   |   |   |-- register_mem_functions.hpp
-|   |   |   |-- template_encoding.hpp
-|   |   |   |-- template_template_param.hpp
-|   |   |   |-- type_encoding.hpp
-|   |   |   |-- typeof.hpp
-|   |   |   |-- typeof_impl.hpp
-|   |   |   |-- type_template_param.hpp
-|   |   |   |-- unsupported.hpp
-|   |   |   |-- vector100.hpp
-|   |   |   |-- vector150.hpp
-|   |   |   |-- vector200.hpp
-|   |   |   |-- vector50.hpp
-|   |   |   `-- vector.hpp
-|   |   |-- type_traits
-|   |   |   |-- detail
-|   |   |   |   |-- bool_trait_undef.hpp
-|   |   |   |   |-- common_arithmetic_type.hpp
-|   |   |   |   |-- common_type_impl.hpp
-|   |   |   |   |-- composite_member_pointer_type.hpp
-|   |   |   |   |-- composite_pointer_type.hpp
-|   |   |   |   |-- config.hpp
-|   |   |   |   |-- has_binary_operator.hpp
-|   |   |   |   |-- has_postfix_operator.hpp
-|   |   |   |   |-- has_prefix_operator.hpp
-|   |   |   |   |-- is_function_cxx_03.hpp
-|   |   |   |   |-- is_function_cxx_11.hpp
-|   |   |   |   |-- is_function_msvc10_fix.hpp
-|   |   |   |   |-- is_function_ptr_helper.hpp
-|   |   |   |   |-- is_function_ptr_tester.hpp
-|   |   |   |   |-- is_likely_lambda.hpp
-|   |   |   |   |-- is_member_function_pointer_cxx_03.hpp
-|   |   |   |   |-- is_member_function_pointer_cxx_11.hpp
-|   |   |   |   |-- is_mem_fun_pointer_impl.hpp
-|   |   |   |   |-- is_mem_fun_pointer_tester.hpp
-|   |   |   |   |-- is_rvalue_reference_msvc10_fix.hpp
-|   |   |   |   |-- mp_defer.hpp
-|   |   |   |   `-- yes_no_type.hpp
-|   |   |   |-- add_const.hpp
-|   |   |   |-- add_cv.hpp
-|   |   |   |-- add_lvalue_reference.hpp
-|   |   |   |-- add_pointer.hpp
-|   |   |   |-- add_reference.hpp
-|   |   |   |-- add_rvalue_reference.hpp
-|   |   |   |-- add_volatile.hpp
-|   |   |   |-- aligned_storage.hpp
-|   |   |   |-- alignment_of.hpp
-|   |   |   |-- common_type.hpp
-|   |   |   |-- composite_traits.hpp
-|   |   |   |-- conditional.hpp
-|   |   |   |-- conversion_traits.hpp
-|   |   |   |-- copy_cv.hpp
-|   |   |   |-- copy_cv_ref.hpp
-|   |   |   |-- copy_reference.hpp
-|   |   |   |-- cv_traits.hpp
-|   |   |   |-- decay.hpp
-|   |   |   |-- declval.hpp
-|   |   |   |-- enable_if.hpp
-|   |   |   |-- extent.hpp
-|   |   |   |-- floating_point_promotion.hpp
-|   |   |   |-- function_traits.hpp
-|   |   |   |-- has_bit_and_assign.hpp
-|   |   |   |-- has_bit_and.hpp
-|   |   |   |-- has_bit_or_assign.hpp
-|   |   |   |-- has_bit_or.hpp
-|   |   |   |-- has_bit_xor_assign.hpp
-|   |   |   |-- has_bit_xor.hpp
-|   |   |   |-- has_complement.hpp
-|   |   |   |-- has_dereference.hpp
-|   |   |   |-- has_divides_assign.hpp
-|   |   |   |-- has_divides.hpp
-|   |   |   |-- has_equal_to.hpp
-|   |   |   |-- has_greater_equal.hpp
-|   |   |   |-- has_greater.hpp
-|   |   |   |-- has_left_shift_assign.hpp
-|   |   |   |-- has_left_shift.hpp
-|   |   |   |-- has_less_equal.hpp
-|   |   |   |-- has_less.hpp
-|   |   |   |-- has_logical_and.hpp
-|   |   |   |-- has_logical_not.hpp
-|   |   |   |-- has_logical_or.hpp
-|   |   |   |-- has_minus_assign.hpp
-|   |   |   |-- has_minus.hpp
-|   |   |   |-- has_modulus_assign.hpp
-|   |   |   |-- has_modulus.hpp
-|   |   |   |-- has_multiplies_assign.hpp
-|   |   |   |-- has_multiplies.hpp
-|   |   |   |-- has_negate.hpp
-|   |   |   |-- has_new_operator.hpp
-|   |   |   |-- has_not_equal_to.hpp
-|   |   |   |-- has_nothrow_assign.hpp
-|   |   |   |-- has_nothrow_constructor.hpp
-|   |   |   |-- has_nothrow_copy.hpp
-|   |   |   |-- has_nothrow_destructor.hpp
-|   |   |   |-- has_plus_assign.hpp
-|   |   |   |-- has_plus.hpp
-|   |   |   |-- has_post_decrement.hpp
-|   |   |   |-- has_post_increment.hpp
-|   |   |   |-- has_pre_decrement.hpp
-|   |   |   |-- has_pre_increment.hpp
-|   |   |   |-- has_right_shift_assign.hpp
-|   |   |   |-- has_right_shift.hpp
-|   |   |   |-- has_trivial_assign.hpp
-|   |   |   |-- has_trivial_constructor.hpp
-|   |   |   |-- has_trivial_copy.hpp
-|   |   |   |-- has_trivial_destructor.hpp
-|   |   |   |-- has_trivial_move_assign.hpp
-|   |   |   |-- has_trivial_move_constructor.hpp
-|   |   |   |-- has_unary_minus.hpp
-|   |   |   |-- has_unary_plus.hpp
-|   |   |   |-- has_virtual_destructor.hpp
-|   |   |   |-- integral_constant.hpp
-|   |   |   |-- integral_promotion.hpp
-|   |   |   |-- intrinsics.hpp
-|   |   |   |-- is_abstract.hpp
-|   |   |   |-- is_arithmetic.hpp
-|   |   |   |-- is_array.hpp
-|   |   |   |-- is_assignable.hpp
-|   |   |   |-- is_base_and_derived.hpp
-|   |   |   |-- is_base_of.hpp
-|   |   |   |-- is_bounded_array.hpp
-|   |   |   |-- is_class.hpp
-|   |   |   |-- is_complete.hpp
-|   |   |   |-- is_complex.hpp
-|   |   |   |-- is_compound.hpp
-|   |   |   |-- is_const.hpp
-|   |   |   |-- is_constructible.hpp
-|   |   |   |-- is_convertible.hpp
-|   |   |   |-- is_copy_assignable.hpp
-|   |   |   |-- is_copy_constructible.hpp
-|   |   |   |-- is_default_constructible.hpp
-|   |   |   |-- is_destructible.hpp
-|   |   |   |-- is_empty.hpp
-|   |   |   |-- is_enum.hpp
-|   |   |   |-- is_final.hpp
-|   |   |   |-- is_float.hpp
-|   |   |   |-- is_floating_point.hpp
-|   |   |   |-- is_function.hpp
-|   |   |   |-- is_fundamental.hpp
-|   |   |   |-- is_integral.hpp
-|   |   |   |-- is_list_constructible.hpp
-|   |   |   |-- is_lvalue_reference.hpp
-|   |   |   |-- is_member_function_pointer.hpp
-|   |   |   |-- is_member_object_pointer.hpp
-|   |   |   |-- is_member_pointer.hpp
-|   |   |   |-- is_noncopyable.hpp
-|   |   |   |-- is_nothrow_move_assignable.hpp
-|   |   |   |-- is_nothrow_move_constructible.hpp
-|   |   |   |-- is_nothrow_swappable.hpp
-|   |   |   |-- is_object.hpp
-|   |   |   |-- is_pod.hpp
-|   |   |   |-- is_pointer.hpp
-|   |   |   |-- is_polymorphic.hpp
-|   |   |   |-- is_reference.hpp
-|   |   |   |-- is_rvalue_reference.hpp
-|   |   |   |-- is_same.hpp
-|   |   |   |-- is_scalar.hpp
-|   |   |   |-- is_signed.hpp
-|   |   |   |-- is_stateless.hpp
-|   |   |   |-- is_unbounded_array.hpp
-|   |   |   |-- is_union.hpp
-|   |   |   |-- is_unsigned.hpp
-|   |   |   |-- is_virtual_base_of.hpp
-|   |   |   |-- is_void.hpp
-|   |   |   |-- is_volatile.hpp
-|   |   |   |-- make_signed.hpp
-|   |   |   |-- make_unsigned.hpp
-|   |   |   |-- make_void.hpp
-|   |   |   |-- promote.hpp
-|   |   |   |-- rank.hpp
-|   |   |   |-- remove_all_extents.hpp
-|   |   |   |-- remove_bounds.hpp
-|   |   |   |-- remove_const.hpp
-|   |   |   |-- remove_cv.hpp
-|   |   |   |-- remove_cv_ref.hpp
-|   |   |   |-- remove_extent.hpp
-|   |   |   |-- remove_pointer.hpp
-|   |   |   |-- remove_reference.hpp
-|   |   |   |-- remove_volatile.hpp
-|   |   |   |-- same_traits.hpp
-|   |   |   |-- type_identity.hpp
-|   |   |   `-- type_with_alignment.hpp
-|   |   |-- utility
-|   |   |   |-- detail
-|   |   |   |   |-- in_place_factory_prefix.hpp
-|   |   |   |   |-- in_place_factory_suffix.hpp
-|   |   |   |   `-- result_of_iterate.hpp
-|   |   |   |-- addressof.hpp
-|   |   |   |-- base_from_member.hpp
-|   |   |   |-- binary.hpp
-|   |   |   |-- compare_pointees.hpp
-|   |   |   |-- declval.hpp
-|   |   |   |-- enable_if.hpp
-|   |   |   |-- explicit_operator_bool.hpp
-|   |   |   |-- identity_type.hpp
-|   |   |   |-- in_place_factory.hpp
-|   |   |   |-- result_of.hpp
-|   |   |   |-- swap.hpp
-|   |   |   |-- typed_in_place_factory.hpp
-|   |   |   `-- value_init.hpp
-|   |   |-- winapi
-|   |   |   |-- basic_types.hpp
-|   |   |   |-- character_code_conversion.hpp
-|   |   |   |-- config.hpp
-|   |   |   |-- dll.hpp
-|   |   |   |-- error_codes.hpp
-|   |   |   |-- error_handling.hpp
-|   |   |   |-- get_current_process.hpp
-|   |   |   |-- get_current_thread.hpp
-|   |   |   |-- get_last_error.hpp
-|   |   |   |-- get_process_times.hpp
-|   |   |   |-- get_thread_times.hpp
-|   |   |   |-- local_memory.hpp
-|   |   |   |-- time.hpp
-|   |   |   `-- timers.hpp
-|   |   |-- aligned_storage.hpp
-|   |   |-- any.hpp
-|   |   |-- array.hpp
-|   |   |-- assert.hpp
-|   |   |-- bind.hpp
-|   |   |-- blank_fwd.hpp
-|   |   |-- blank.hpp
-|   |   |-- call_traits.hpp
-|   |   |-- cast.hpp
-|   |   |-- cerrno.hpp
-|   |   |-- checked_delete.hpp
-|   |   |-- concept_archetype.hpp
-|   |   |-- concept_check.hpp
-|   |   |-- config.hpp
-|   |   |-- cstdint.hpp
-|   |   |-- cstdlib.hpp
-|   |   |-- current_function.hpp
-|   |   |-- filesystem.hpp
-|   |   |-- format.hpp
-|   |   |-- function_equal.hpp
-|   |   |-- function.hpp
-|   |   |-- function_output_iterator.hpp
-|   |   |-- generator_iterator.hpp
-|   |   |-- get_pointer.hpp
-|   |   |-- implicit_cast.hpp
-|   |   |-- indirect_reference.hpp
-|   |   |-- integer_fwd.hpp
-|   |   |-- integer.hpp
-|   |   |-- integer_traits.hpp
-|   |   |-- io_fwd.hpp
-|   |   |-- is_placeholder.hpp
-|   |   |-- iterator_adaptors.hpp
-|   |   |-- iterator.hpp
-|   |   |-- lexical_cast.hpp
-|   |   |-- limits.hpp
-|   |   |-- make_shared.hpp
-|   |   |-- mem_fn.hpp
-|   |   |-- mp11.hpp
-|   |   |-- next_prior.hpp
-|   |   |-- noncopyable.hpp
-|   |   |-- none.hpp
-|   |   |-- none_t.hpp
-|   |   |-- non_type.hpp
-|   |   |-- operators.hpp
-|   |   |-- optional.hpp
-|   |   |-- pointee.hpp
-|   |   |-- polymorphic_cast.hpp
-|   |   |-- predef.h
-|   |   |-- program_options.hpp
-|   |   |-- rational.hpp
-|   |   |-- ref.hpp
-|   |   |-- scoped_array.hpp
-|   |   |-- scoped_ptr.hpp
-|   |   |-- shared_container_iterator.hpp
-|   |   |-- shared_ptr.hpp
-|   |   |-- static_assert.hpp
-|   |   |-- swap.hpp
-|   |   |-- throw_exception.hpp
-|   |   |-- timer.hpp
-|   |   |-- token_functions.hpp
-|   |   |-- token_iterator.hpp
-|   |   |-- tokenizer.hpp
-|   |   |-- type.hpp
-|   |   |-- type_index.hpp
-|   |   |-- type_traits.hpp
-|   |   |-- utility.hpp
-|   |   |-- version.hpp
-|   |   `-- visit_each.hpp
-|   |-- catch2
-|   |   `-- catch.hpp
-|   |-- eigen-eigen-b3f3d4950030
-|   |   |-- bench
-|   |   |   |-- btl
-|   |   |   |   |-- actions
-|   |   |   |   |   |-- action_aat_product.hh
-|   |   |   |   |   |-- action_ata_product.hh
-|   |   |   |   |   |-- action_atv_product.hh
-|   |   |   |   |   |-- action_axpby.hh
-|   |   |   |   |   |-- action_axpy.hh
-|   |   |   |   |   |-- action_cholesky.hh
-|   |   |   |   |   |-- action_ger.hh
-|   |   |   |   |   |-- action_hessenberg.hh
-|   |   |   |   |   |-- action_lu_decomp.hh
-|   |   |   |   |   |-- action_lu_solve.hh
-|   |   |   |   |   |-- action_matrix_matrix_product_bis.hh
-|   |   |   |   |   |-- action_matrix_matrix_product.hh
-|   |   |   |   |   |-- action_matrix_vector_product.hh
-|   |   |   |   |   |-- action_partial_lu.hh
-|   |   |   |   |   |-- action_rot.hh
-|   |   |   |   |   |-- action_symv.hh
-|   |   |   |   |   |-- action_syr2.hh
-|   |   |   |   |   |-- action_trisolve.hh
-|   |   |   |   |   |-- action_trisolve_matrix.hh
-|   |   |   |   |   |-- action_trmm.hh
-|   |   |   |   |   `-- basic_actions.hh
-|   |   |   |   |-- cmake
-|   |   |   |   |   |-- FindACML.cmake
-|   |   |   |   |   |-- FindATLAS.cmake
-|   |   |   |   |   |-- FindBLAZE.cmake
-|   |   |   |   |   |-- FindBlitz.cmake
-|   |   |   |   |   |-- FindCBLAS.cmake
-|   |   |   |   |   |-- FindGMM.cmake
-|   |   |   |   |   |-- FindMKL.cmake
-|   |   |   |   |   |-- FindMTL4.cmake
-|   |   |   |   |   |-- FindOPENBLAS.cmake
-|   |   |   |   |   |-- FindPackageHandleStandardArgs.cmake
-|   |   |   |   |   |-- FindTvmet.cmake
-|   |   |   |   |   `-- MacroOptionalAddSubdirectory.cmake
-|   |   |   |   |-- data
-|   |   |   |   |   |-- action_settings.txt
-|   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |-- gnuplot_common_settings.hh
-|   |   |   |   |   |-- go_mean
-|   |   |   |   |   |-- mean.cxx
-|   |   |   |   |   |-- mk_gnuplot_script.sh
-|   |   |   |   |   |-- mk_mean_script.sh
-|   |   |   |   |   |-- mk_new_gnuplot.sh
-|   |   |   |   |   |-- perlib_plot_settings.txt
-|   |   |   |   |   |-- regularize.cxx
-|   |   |   |   |   |-- smooth_all.sh
-|   |   |   |   |   `-- smooth.cxx
-|   |   |   |   |-- generic_bench
-|   |   |   |   |   |-- init
-|   |   |   |   |   |   |-- init_function.hh
-|   |   |   |   |   |   |-- init_matrix.hh
-|   |   |   |   |   |   `-- init_vector.hh
-|   |   |   |   |   |-- static
-|   |   |   |   |   |   |-- bench_static.hh
-|   |   |   |   |   |   |-- intel_bench_fixed_size.hh
-|   |   |   |   |   |   `-- static_size_generator.hh
-|   |   |   |   |   |-- timers
-|   |   |   |   |   |   |-- mixed_perf_analyzer.hh
-|   |   |   |   |   |   |-- portable_perf_analyzer.hh
-|   |   |   |   |   |   |-- portable_perf_analyzer_old.hh
-|   |   |   |   |   |   |-- portable_timer.hh
-|   |   |   |   |   |   |-- STL_perf_analyzer.hh
-|   |   |   |   |   |   |-- STL_timer.hh
-|   |   |   |   |   |   |-- x86_perf_analyzer.hh
-|   |   |   |   |   |   `-- x86_timer.hh
-|   |   |   |   |   |-- utils
-|   |   |   |   |   |   |-- size_lin_log.hh
-|   |   |   |   |   |   |-- size_log.hh
-|   |   |   |   |   |   |-- utilities.h
-|   |   |   |   |   |   `-- xy_file.hh
-|   |   |   |   |   |-- bench.hh
-|   |   |   |   |   |-- bench_parameter.hh
-|   |   |   |   |   `-- btl.hh
-|   |   |   |   |-- libs
-|   |   |   |   |   |-- BLAS
-|   |   |   |   |   |   |-- blas.h
-|   |   |   |   |   |   |-- blas_interface.hh
-|   |   |   |   |   |   |-- blas_interface_impl.hh
-|   |   |   |   |   |   |-- c_interface_base.h
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   `-- main.cpp
-|   |   |   |   |   |-- blaze
-|   |   |   |   |   |   |-- blaze_interface.hh
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   `-- main.cpp
-|   |   |   |   |   |-- blitz
-|   |   |   |   |   |   |-- blitz_interface.hh
-|   |   |   |   |   |   |-- blitz_LU_solve_interface.hh
-|   |   |   |   |   |   |-- btl_blitz.cpp
-|   |   |   |   |   |   |-- btl_tiny_blitz.cpp
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   `-- tiny_blitz_interface.hh
-|   |   |   |   |   |-- eigen2
-|   |   |   |   |   |   |-- btl_tiny_eigen2.cpp
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- eigen2_interface.hh
-|   |   |   |   |   |   |-- main_adv.cpp
-|   |   |   |   |   |   |-- main_linear.cpp
-|   |   |   |   |   |   |-- main_matmat.cpp
-|   |   |   |   |   |   `-- main_vecmat.cpp
-|   |   |   |   |   |-- eigen3
-|   |   |   |   |   |   |-- btl_tiny_eigen3.cpp
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- eigen3_interface.hh
-|   |   |   |   |   |   |-- main_adv.cpp
-|   |   |   |   |   |   |-- main_linear.cpp
-|   |   |   |   |   |   |-- main_matmat.cpp
-|   |   |   |   |   |   `-- main_vecmat.cpp
-|   |   |   |   |   |-- gmm
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- gmm_interface.hh
-|   |   |   |   |   |   |-- gmm_LU_solve_interface.hh
-|   |   |   |   |   |   `-- main.cpp
-|   |   |   |   |   |-- mtl4
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- main.cpp
-|   |   |   |   |   |   |-- mtl4_interface.hh
-|   |   |   |   |   |   `-- mtl4_LU_solve_interface.hh
-|   |   |   |   |   |-- STL
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- main.cpp
-|   |   |   |   |   |   `-- STL_interface.hh
-|   |   |   |   |   |-- tensors
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- main_linear.cpp
-|   |   |   |   |   |   |-- main_matmat.cpp
-|   |   |   |   |   |   |-- main_vecmat.cpp
-|   |   |   |   |   |   `-- tensor_interface.hh
-|   |   |   |   |   |-- tvmet
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- main.cpp
-|   |   |   |   |   |   `-- tvmet_interface.hh
-|   |   |   |   |   `-- ublas
-|   |   |   |   |       |-- CMakeLists.txt
-|   |   |   |   |       |-- main.cpp
-|   |   |   |   |       `-- ublas_interface.hh
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- COPYING
-|   |   |   |   `-- README
-|   |   |   |-- perf_monitoring
-|   |   |   |   `-- gemm
-|   |   |   |       |-- changesets.txt
-|   |   |   |       |-- gemm.cpp
-|   |   |   |       |-- gemm_settings.txt
-|   |   |   |       |-- lazy_gemm.cpp
-|   |   |   |       |-- lazy_gemm_settings.txt
-|   |   |   |       |-- make_plot.sh
-|   |   |   |       `-- run.sh
-|   |   |   |-- spbench
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- spbench.dtd
-|   |   |   |   |-- spbenchsolver.cpp
-|   |   |   |   |-- spbenchsolver.h
-|   |   |   |   |-- spbenchstyle.h
-|   |   |   |   |-- sp_solver.cpp
-|   |   |   |   `-- test_sparseLU.cpp
-|   |   |   |-- tensors
-|   |   |   |   |-- benchmark.h
-|   |   |   |   |-- benchmark_main.cc
-|   |   |   |   |-- contraction_benchmarks_cpu.cc
-|   |   |   |   |-- README
-|   |   |   |   |-- tensor_benchmarks_cpu.cc
-|   |   |   |   |-- tensor_benchmarks_fp16_gpu.cu
-|   |   |   |   |-- tensor_benchmarks_gpu.cu
-|   |   |   |   |-- tensor_benchmarks.h
-|   |   |   |   `-- tensor_benchmarks_sycl.cc
-|   |   |   |-- analyze-blocking-sizes.cpp
-|   |   |   |-- basicbench.cxxlist
-|   |   |   |-- basicbenchmark.cpp
-|   |   |   |-- basicbenchmark.h
-|   |   |   |-- benchBlasGemm.cpp
-|   |   |   |-- benchCholesky.cpp
-|   |   |   |-- benchEigenSolver.cpp
-|   |   |   |-- benchFFT.cpp
-|   |   |   |-- bench_gemm.cpp
-|   |   |   |-- benchGeometry.cpp
-|   |   |   |-- benchmark-blocking-sizes.cpp
-|   |   |   |-- benchmark.cpp
-|   |   |   |-- benchmarkSlice.cpp
-|   |   |   |-- benchmark_suite
-|   |   |   |-- benchmarkX.cpp
-|   |   |   |-- benchmarkXcwise.cpp
-|   |   |   |-- bench_multi_compilers.sh
-|   |   |   |-- bench_norm.cpp
-|   |   |   |-- bench_reverse.cpp
-|   |   |   |-- BenchSparseUtil.h
-|   |   |   |-- bench_sum.cpp
-|   |   |   |-- BenchTimer.h
-|   |   |   |-- bench_unrolling
-|   |   |   |-- BenchUtil.h
-|   |   |   |-- benchVecAdd.cpp
-|   |   |   |-- check_cache_queries.cpp
-|   |   |   |-- dense_solvers.cpp
-|   |   |   |-- eig33.cpp
-|   |   |   |-- geometry.cpp
-|   |   |   |-- product_threshold.cpp
-|   |   |   |-- quatmul.cpp
-|   |   |   |-- quat_slerp.cpp
-|   |   |   |-- README.txt
-|   |   |   |-- sparse_cholesky.cpp
-|   |   |   |-- sparse_dense_product.cpp
-|   |   |   |-- sparse_lu.cpp
-|   |   |   |-- sparse_product.cpp
-|   |   |   |-- sparse_randomsetter.cpp
-|   |   |   |-- sparse_setter.cpp
-|   |   |   |-- sparse_transpose.cpp
-|   |   |   |-- sparse_trisolver.cpp
-|   |   |   |-- spmv.cpp
-|   |   |   `-- vdw_new.cpp
-|   |   |-- blas
-|   |   |   |-- f2c
-|   |   |   |   |-- chbmv.c
-|   |   |   |   |-- chpmv.c
-|   |   |   |   |-- complexdots.c
-|   |   |   |   |-- ctbmv.c
-|   |   |   |   |-- datatypes.h
-|   |   |   |   |-- d_cnjg.c
-|   |   |   |   |-- drotm.c
-|   |   |   |   |-- drotmg.c
-|   |   |   |   |-- dsbmv.c
-|   |   |   |   |-- dspmv.c
-|   |   |   |   |-- dtbmv.c
-|   |   |   |   |-- lsame.c
-|   |   |   |   |-- r_cnjg.c
-|   |   |   |   |-- srotm.c
-|   |   |   |   |-- srotmg.c
-|   |   |   |   |-- ssbmv.c
-|   |   |   |   |-- sspmv.c
-|   |   |   |   |-- stbmv.c
-|   |   |   |   |-- zhbmv.c
-|   |   |   |   |-- zhpmv.c
-|   |   |   |   `-- ztbmv.c
-|   |   |   |-- fortran
-|   |   |   |   `-- complexdots.f
-|   |   |   |-- testing
-|   |   |   |   |-- cblat1.f
-|   |   |   |   |-- cblat2.dat
-|   |   |   |   |-- cblat2.f
-|   |   |   |   |-- cblat3.dat
-|   |   |   |   |-- cblat3.f
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- dblat1.f
-|   |   |   |   |-- dblat2.dat
-|   |   |   |   |-- dblat2.f
-|   |   |   |   |-- dblat3.dat
-|   |   |   |   |-- dblat3.f
-|   |   |   |   |-- runblastest.sh
-|   |   |   |   |-- sblat1.f
-|   |   |   |   |-- sblat2.dat
-|   |   |   |   |-- sblat2.f
-|   |   |   |   |-- sblat3.dat
-|   |   |   |   |-- sblat3.f
-|   |   |   |   |-- zblat1.f
-|   |   |   |   |-- zblat2.dat
-|   |   |   |   |-- zblat2.f
-|   |   |   |   |-- zblat3.dat
-|   |   |   |   `-- zblat3.f
-|   |   |   |-- BandTriangularSolver.h
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- common.h
-|   |   |   |-- complex_double.cpp
-|   |   |   |-- complex_single.cpp
-|   |   |   |-- double.cpp
-|   |   |   |-- GeneralRank1Update.h
-|   |   |   |-- level1_cplx_impl.h
-|   |   |   |-- level1_impl.h
-|   |   |   |-- level1_real_impl.h
-|   |   |   |-- level2_cplx_impl.h
-|   |   |   |-- level2_impl.h
-|   |   |   |-- level2_real_impl.h
-|   |   |   |-- level3_impl.h
-|   |   |   |-- PackedSelfadjointProduct.h
-|   |   |   |-- PackedTriangularMatrixVector.h
-|   |   |   |-- PackedTriangularSolverVector.h
-|   |   |   |-- Rank2Update.h
-|   |   |   |-- README.txt
-|   |   |   |-- single.cpp
-|   |   |   `-- xerbla.cpp
-|   |   |-- cmake
-|   |   |   |-- Eigen3Config.cmake.in
-|   |   |   |-- Eigen3ConfigLegacy.cmake.in
-|   |   |   |-- EigenConfigureTesting.cmake
-|   |   |   |-- EigenDetermineOSVersion.cmake
-|   |   |   |-- EigenDetermineVSServicePack.cmake
-|   |   |   |-- EigenTesting.cmake
-|   |   |   |-- EigenUninstall.cmake
-|   |   |   |-- FindAdolc.cmake
-|   |   |   |-- FindBLAS.cmake
-|   |   |   |-- FindBLASEXT.cmake
-|   |   |   |-- FindCholmod.cmake
-|   |   |   |-- FindComputeCpp.cmake
-|   |   |   |-- FindEigen2.cmake
-|   |   |   |-- FindEigen3.cmake
-|   |   |   |-- FindFFTW.cmake
-|   |   |   |-- FindGLEW.cmake
-|   |   |   |-- FindGMP.cmake
-|   |   |   |-- FindGoogleHash.cmake
-|   |   |   |-- FindGSL.cmake
-|   |   |   |-- FindHWLOC.cmake
-|   |   |   |-- FindLAPACK.cmake
-|   |   |   |-- FindMetis.cmake
-|   |   |   |-- FindMPFR.cmake
-|   |   |   |-- FindPastix.cmake
-|   |   |   |-- FindPTSCOTCH.cmake
-|   |   |   |-- FindScotch.cmake
-|   |   |   |-- FindSPQR.cmake
-|   |   |   |-- FindStandardMathLibrary.cmake
-|   |   |   |-- FindSuperLU.cmake
-|   |   |   |-- FindUmfpack.cmake
-|   |   |   |-- language_support.cmake
-|   |   |   |-- RegexUtils.cmake
-|   |   |   `-- UseEigen3.cmake
-|   |   |-- debug
-|   |   |   |-- gdb
-|   |   |   |   |-- __init__.py
-|   |   |   |   `-- printers.py
-|   |   |   `-- msvc
-|   |   |       |-- eigen_autoexp_part.dat
-|   |   |       `-- eigen.natvis
-|   |   |-- demos
-|   |   |   |-- mandelbrot
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- mandelbrot.cpp
-|   |   |   |   |-- mandelbrot.h
-|   |   |   |   `-- README
-|   |   |   |-- mix_eigen_and_c
-|   |   |   |   |-- binary_library.cpp
-|   |   |   |   |-- binary_library.h
-|   |   |   |   |-- example.c
-|   |   |   |   `-- README
-|   |   |   |-- opengl
-|   |   |   |   |-- camera.cpp
-|   |   |   |   |-- camera.h
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- gpuhelper.cpp
-|   |   |   |   |-- gpuhelper.h
-|   |   |   |   |-- icosphere.cpp
-|   |   |   |   |-- icosphere.h
-|   |   |   |   |-- quaternion_demo.cpp
-|   |   |   |   |-- quaternion_demo.h
-|   |   |   |   |-- README
-|   |   |   |   |-- trackball.cpp
-|   |   |   |   `-- trackball.h
-|   |   |   `-- CMakeLists.txt
-|   |   |-- doc
-|   |   |   |-- examples
-|   |   |   |   |-- class_Block.cpp
-|   |   |   |   |-- class_CwiseBinaryOp.cpp
-|   |   |   |   |-- class_CwiseUnaryOp.cpp
-|   |   |   |   |-- class_CwiseUnaryOp_ptrfun.cpp
-|   |   |   |   |-- class_FixedBlock.cpp
-|   |   |   |   |-- class_FixedVectorBlock.cpp
-|   |   |   |   |-- class_VectorBlock.cpp
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- CustomizingEigen_Inheritance.cpp
-|   |   |   |   |-- Cwise_erfc.cpp
-|   |   |   |   |-- Cwise_erf.cpp
-|   |   |   |   |-- Cwise_lgamma.cpp
-|   |   |   |   |-- DenseBase_middleCols_int.cpp
-|   |   |   |   |-- DenseBase_middleRows_int.cpp
-|   |   |   |   |-- DenseBase_template_int_middleCols.cpp
-|   |   |   |   |-- DenseBase_template_int_middleRows.cpp
-|   |   |   |   |-- function_taking_eigenbase.cpp
-|   |   |   |   |-- function_taking_ref.cpp
-|   |   |   |   |-- make_circulant2.cpp
-|   |   |   |   |-- make_circulant.cpp
-|   |   |   |   |-- make_circulant.cpp.entry
-|   |   |   |   |-- make_circulant.cpp.evaluator
-|   |   |   |   |-- make_circulant.cpp.expression
-|   |   |   |   |-- make_circulant.cpp.main
-|   |   |   |   |-- make_circulant.cpp.preamble
-|   |   |   |   |-- make_circulant.cpp.traits
-|   |   |   |   |-- matrixfree_cg.cpp
-|   |   |   |   |-- nullary_indexing.cpp
-|   |   |   |   |-- QuickStart_example2_dynamic.cpp
-|   |   |   |   |-- QuickStart_example2_fixed.cpp
-|   |   |   |   |-- QuickStart_example.cpp
-|   |   |   |   |-- TemplateKeyword_flexible.cpp
-|   |   |   |   |-- TemplateKeyword_simple.cpp
-|   |   |   |   |-- tut_arithmetic_add_sub.cpp
-|   |   |   |   |-- tut_arithmetic_dot_cross.cpp
-|   |   |   |   |-- tut_arithmetic_matrix_mul.cpp
-|   |   |   |   |-- tut_arithmetic_redux_basic.cpp
-|   |   |   |   |-- tut_arithmetic_scalar_mul_div.cpp
-|   |   |   |   |-- tut_matrix_coefficient_accessors.cpp
-|   |   |   |   |-- tut_matrix_resize.cpp
-|   |   |   |   |-- tut_matrix_resize_fixed_size.cpp
-|   |   |   |   |-- Tutorial_ArrayClass_accessors.cpp
-|   |   |   |   |-- Tutorial_ArrayClass_addition.cpp
-|   |   |   |   |-- Tutorial_ArrayClass_cwise_other.cpp
-|   |   |   |   |-- Tutorial_ArrayClass_interop.cpp
-|   |   |   |   |-- Tutorial_ArrayClass_interop_matrix.cpp
-|   |   |   |   |-- Tutorial_ArrayClass_mult.cpp
-|   |   |   |   |-- Tutorial_BlockOperations_block_assignment.cpp
-|   |   |   |   |-- Tutorial_BlockOperations_colrow.cpp
-|   |   |   |   |-- Tutorial_BlockOperations_corner.cpp
-|   |   |   |   |-- Tutorial_BlockOperations_print_block.cpp
-|   |   |   |   |-- Tutorial_BlockOperations_vector.cpp
-|   |   |   |   |-- TutorialInplaceLU.cpp
-|   |   |   |   |-- TutorialLinAlgComputeTwice.cpp
-|   |   |   |   |-- TutorialLinAlgExComputeSolveError.cpp
-|   |   |   |   |-- TutorialLinAlgExSolveColPivHouseholderQR.cpp
-|   |   |   |   |-- TutorialLinAlgExSolveLDLT.cpp
-|   |   |   |   |-- TutorialLinAlgInverseDeterminant.cpp
-|   |   |   |   |-- TutorialLinAlgRankRevealing.cpp
-|   |   |   |   |-- TutorialLinAlgSelfAdjointEigenSolver.cpp
-|   |   |   |   |-- TutorialLinAlgSetThreshold.cpp
-|   |   |   |   |-- TutorialLinAlgSVDSolve.cpp
-|   |   |   |   |-- Tutorial_PartialLU_solve.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp
-|   |   |   |   |-- Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp
-|   |   |   |   |-- Tutorial_simple_example_dynamic_size.cpp
-|   |   |   |   `-- Tutorial_simple_example_fixed_size.cpp
-|   |   |   |-- snippets
-|   |   |   |   |-- AngleAxis_mimic_euler.cpp
-|   |   |   |   |-- BiCGSTAB_simple.cpp
-|   |   |   |   |-- BiCGSTAB_step_by_step.cpp
-|   |   |   |   |-- class_FullPivLU.cpp
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- ColPivHouseholderQR_solve.cpp
-|   |   |   |   |-- compile_snippet.cpp.in
-|   |   |   |   |-- ComplexEigenSolver_compute.cpp
-|   |   |   |   |-- ComplexEigenSolver_eigenvalues.cpp
-|   |   |   |   |-- ComplexEigenSolver_eigenvectors.cpp
-|   |   |   |   |-- ComplexSchur_compute.cpp
-|   |   |   |   |-- ComplexSchur_matrixT.cpp
-|   |   |   |   |-- ComplexSchur_matrixU.cpp
-|   |   |   |   |-- Cwise_abs2.cpp
-|   |   |   |   |-- Cwise_abs.cpp
-|   |   |   |   |-- Cwise_acos.cpp
-|   |   |   |   |-- Cwise_arg.cpp
-|   |   |   |   |-- Cwise_array_power_array.cpp
-|   |   |   |   |-- Cwise_asin.cpp
-|   |   |   |   |-- Cwise_atan.cpp
-|   |   |   |   |-- Cwise_boolean_and.cpp
-|   |   |   |   |-- Cwise_boolean_not.cpp
-|   |   |   |   |-- Cwise_boolean_or.cpp
-|   |   |   |   |-- Cwise_boolean_xor.cpp
-|   |   |   |   |-- Cwise_ceil.cpp
-|   |   |   |   |-- Cwise_cos.cpp
-|   |   |   |   |-- Cwise_cosh.cpp
-|   |   |   |   |-- Cwise_cube.cpp
-|   |   |   |   |-- Cwise_equal_equal.cpp
-|   |   |   |   |-- Cwise_exp.cpp
-|   |   |   |   |-- Cwise_floor.cpp
-|   |   |   |   |-- Cwise_greater.cpp
-|   |   |   |   |-- Cwise_greater_equal.cpp
-|   |   |   |   |-- Cwise_inverse.cpp
-|   |   |   |   |-- Cwise_isFinite.cpp
-|   |   |   |   |-- Cwise_isInf.cpp
-|   |   |   |   |-- Cwise_isNaN.cpp
-|   |   |   |   |-- Cwise_less.cpp
-|   |   |   |   |-- Cwise_less_equal.cpp
-|   |   |   |   |-- Cwise_log10.cpp
-|   |   |   |   |-- Cwise_log.cpp
-|   |   |   |   |-- Cwise_max.cpp
-|   |   |   |   |-- Cwise_min.cpp
-|   |   |   |   |-- Cwise_minus.cpp
-|   |   |   |   |-- Cwise_minus_equal.cpp
-|   |   |   |   |-- Cwise_not_equal.cpp
-|   |   |   |   |-- Cwise_plus.cpp
-|   |   |   |   |-- Cwise_plus_equal.cpp
-|   |   |   |   |-- Cwise_pow.cpp
-|   |   |   |   |-- Cwise_product.cpp
-|   |   |   |   |-- Cwise_quotient.cpp
-|   |   |   |   |-- Cwise_round.cpp
-|   |   |   |   |-- Cwise_scalar_power_array.cpp
-|   |   |   |   |-- Cwise_sign.cpp
-|   |   |   |   |-- Cwise_sin.cpp
-|   |   |   |   |-- Cwise_sinh.cpp
-|   |   |   |   |-- Cwise_slash_equal.cpp
-|   |   |   |   |-- Cwise_sqrt.cpp
-|   |   |   |   |-- Cwise_square.cpp
-|   |   |   |   |-- Cwise_tan.cpp
-|   |   |   |   |-- Cwise_tanh.cpp
-|   |   |   |   |-- Cwise_times_equal.cpp
-|   |   |   |   |-- DenseBase_LinSpaced.cpp
-|   |   |   |   |-- DenseBase_LinSpacedInt.cpp
-|   |   |   |   |-- DenseBase_LinSpaced_seq.cpp
-|   |   |   |   |-- DenseBase_setLinSpaced.cpp
-|   |   |   |   |-- DirectionWise_hnormalized.cpp
-|   |   |   |   |-- DirectionWise_replicate.cpp
-|   |   |   |   |-- DirectionWise_replicate_int.cpp
-|   |   |   |   |-- EigenSolver_compute.cpp
-|   |   |   |   |-- EigenSolver_EigenSolver_MatrixType.cpp
-|   |   |   |   |-- EigenSolver_eigenvalues.cpp
-|   |   |   |   |-- EigenSolver_eigenvectors.cpp
-|   |   |   |   |-- EigenSolver_pseudoEigenvectors.cpp
-|   |   |   |   |-- FullPivHouseholderQR_solve.cpp
-|   |   |   |   |-- FullPivLU_image.cpp
-|   |   |   |   |-- FullPivLU_kernel.cpp
-|   |   |   |   |-- FullPivLU_solve.cpp
-|   |   |   |   |-- GeneralizedEigenSolver.cpp
-|   |   |   |   |-- HessenbergDecomposition_compute.cpp
-|   |   |   |   |-- HessenbergDecomposition_matrixH.cpp
-|   |   |   |   |-- HessenbergDecomposition_packedMatrix.cpp
-|   |   |   |   |-- HouseholderQR_householderQ.cpp
-|   |   |   |   |-- HouseholderQR_solve.cpp
-|   |   |   |   |-- HouseholderSequence_HouseholderSequence.cpp
-|   |   |   |   |-- IOFormat.cpp
-|   |   |   |   |-- Jacobi_makeGivens.cpp
-|   |   |   |   |-- Jacobi_makeJacobi.cpp
-|   |   |   |   |-- JacobiSVD_basic.cpp
-|   |   |   |   |-- LeastSquaresNormalEquations.cpp
-|   |   |   |   |-- LeastSquaresQR.cpp
-|   |   |   |   |-- LLT_example.cpp
-|   |   |   |   |-- LLT_solve.cpp
-|   |   |   |   |-- Map_general_stride.cpp
-|   |   |   |   |-- Map_inner_stride.cpp
-|   |   |   |   |-- Map_outer_stride.cpp
-|   |   |   |   |-- Map_placement_new.cpp
-|   |   |   |   |-- Map_simple.cpp
-|   |   |   |   |-- MatrixBase_adjoint.cpp
-|   |   |   |   |-- MatrixBase_all.cpp
-|   |   |   |   |-- MatrixBase_applyOnTheLeft.cpp
-|   |   |   |   |-- MatrixBase_applyOnTheRight.cpp
-|   |   |   |   |-- MatrixBase_array_const.cpp
-|   |   |   |   |-- MatrixBase_array.cpp
-|   |   |   |   |-- MatrixBase_asDiagonal.cpp
-|   |   |   |   |-- MatrixBase_block_int_int.cpp
-|   |   |   |   |-- MatrixBase_block_int_int_int_int.cpp
-|   |   |   |   |-- MatrixBase_bottomLeftCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_bottomRightCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_bottomRows_int.cpp
-|   |   |   |   |-- MatrixBase_cast.cpp
-|   |   |   |   |-- MatrixBase_col.cpp
-|   |   |   |   |-- MatrixBase_colwise.cpp
-|   |   |   |   |-- MatrixBase_computeInverseAndDetWithCheck.cpp
-|   |   |   |   |-- MatrixBase_computeInverseWithCheck.cpp
-|   |   |   |   |-- MatrixBase_cwiseAbs2.cpp
-|   |   |   |   |-- MatrixBase_cwiseAbs.cpp
-|   |   |   |   |-- MatrixBase_cwiseEqual.cpp
-|   |   |   |   |-- MatrixBase_cwiseInverse.cpp
-|   |   |   |   |-- MatrixBase_cwiseMax.cpp
-|   |   |   |   |-- MatrixBase_cwiseMin.cpp
-|   |   |   |   |-- MatrixBase_cwiseNotEqual.cpp
-|   |   |   |   |-- MatrixBase_cwiseProduct.cpp
-|   |   |   |   |-- MatrixBase_cwiseQuotient.cpp
-|   |   |   |   |-- MatrixBase_cwiseSign.cpp
-|   |   |   |   |-- MatrixBase_cwiseSqrt.cpp
-|   |   |   |   |-- MatrixBase_diagonal.cpp
-|   |   |   |   |-- MatrixBase_diagonal_int.cpp
-|   |   |   |   |-- MatrixBase_diagonal_template_int.cpp
-|   |   |   |   |-- MatrixBase_eigenvalues.cpp
-|   |   |   |   |-- MatrixBase_end_int.cpp
-|   |   |   |   |-- MatrixBase_eval.cpp
-|   |   |   |   |-- MatrixBase_fixedBlock_int_int.cpp
-|   |   |   |   |-- MatrixBase_hnormalized.cpp
-|   |   |   |   |-- MatrixBase_homogeneous.cpp
-|   |   |   |   |-- MatrixBase_identity.cpp
-|   |   |   |   |-- MatrixBase_identity_int_int.cpp
-|   |   |   |   |-- MatrixBase_inverse.cpp
-|   |   |   |   |-- MatrixBase_isDiagonal.cpp
-|   |   |   |   |-- MatrixBase_isIdentity.cpp
-|   |   |   |   |-- MatrixBase_isOnes.cpp
-|   |   |   |   |-- MatrixBase_isOrthogonal.cpp
-|   |   |   |   |-- MatrixBase_isUnitary.cpp
-|   |   |   |   |-- MatrixBase_isZero.cpp
-|   |   |   |   |-- MatrixBase_leftCols_int.cpp
-|   |   |   |   |-- MatrixBase_noalias.cpp
-|   |   |   |   |-- MatrixBase_ones.cpp
-|   |   |   |   |-- MatrixBase_ones_int.cpp
-|   |   |   |   |-- MatrixBase_ones_int_int.cpp
-|   |   |   |   |-- MatrixBase_operatorNorm.cpp
-|   |   |   |   |-- MatrixBase_prod.cpp
-|   |   |   |   |-- MatrixBase_random.cpp
-|   |   |   |   |-- MatrixBase_random_int.cpp
-|   |   |   |   |-- MatrixBase_random_int_int.cpp
-|   |   |   |   |-- MatrixBase_replicate.cpp
-|   |   |   |   |-- MatrixBase_replicate_int_int.cpp
-|   |   |   |   |-- MatrixBase_reverse.cpp
-|   |   |   |   |-- MatrixBase_rightCols_int.cpp
-|   |   |   |   |-- MatrixBase_row.cpp
-|   |   |   |   |-- MatrixBase_rowwise.cpp
-|   |   |   |   |-- MatrixBase_segment_int_int.cpp
-|   |   |   |   |-- MatrixBase_select.cpp
-|   |   |   |   |-- MatrixBase_selfadjointView.cpp
-|   |   |   |   |-- MatrixBase_set.cpp
-|   |   |   |   |-- MatrixBase_setIdentity.cpp
-|   |   |   |   |-- MatrixBase_setOnes.cpp
-|   |   |   |   |-- MatrixBase_setRandom.cpp
-|   |   |   |   |-- MatrixBase_setZero.cpp
-|   |   |   |   |-- MatrixBase_start_int.cpp
-|   |   |   |   |-- MatrixBase_template_int_bottomRows.cpp
-|   |   |   |   |-- MatrixBase_template_int_end.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_block_int_int_int_int.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_bottomLeftCorner.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_bottomLeftCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_bottomRightCorner.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_bottomRightCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_topLeftCorner.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_topLeftCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_topRightCorner.cpp
-|   |   |   |   |-- MatrixBase_template_int_int_topRightCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_template_int_leftCols.cpp
-|   |   |   |   |-- MatrixBase_template_int_rightCols.cpp
-|   |   |   |   |-- MatrixBase_template_int_segment.cpp
-|   |   |   |   |-- MatrixBase_template_int_start.cpp
-|   |   |   |   |-- MatrixBase_template_int_topRows.cpp
-|   |   |   |   |-- MatrixBase_topLeftCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_topRightCorner_int_int.cpp
-|   |   |   |   |-- MatrixBase_topRows_int.cpp
-|   |   |   |   |-- MatrixBase_transpose.cpp
-|   |   |   |   |-- MatrixBase_triangularView.cpp
-|   |   |   |   |-- MatrixBase_zero.cpp
-|   |   |   |   |-- MatrixBase_zero_int.cpp
-|   |   |   |   |-- MatrixBase_zero_int_int.cpp
-|   |   |   |   |-- Matrix_Map_stride.cpp
-|   |   |   |   |-- Matrix_resize_int.cpp
-|   |   |   |   |-- Matrix_resize_int_int.cpp
-|   |   |   |   |-- Matrix_resize_int_NoChange.cpp
-|   |   |   |   |-- Matrix_resize_NoChange_int.cpp
-|   |   |   |   |-- Matrix_setConstant_int.cpp
-|   |   |   |   |-- Matrix_setConstant_int_int.cpp
-|   |   |   |   |-- Matrix_setIdentity_int_int.cpp
-|   |   |   |   |-- Matrix_setOnes_int.cpp
-|   |   |   |   |-- Matrix_setOnes_int_int.cpp
-|   |   |   |   |-- Matrix_setRandom_int.cpp
-|   |   |   |   |-- Matrix_setRandom_int_int.cpp
-|   |   |   |   |-- Matrix_setZero_int.cpp
-|   |   |   |   |-- Matrix_setZero_int_int.cpp
-|   |   |   |   |-- PartialPivLU_solve.cpp
-|   |   |   |   |-- PartialRedux_count.cpp
-|   |   |   |   |-- PartialRedux_maxCoeff.cpp
-|   |   |   |   |-- PartialRedux_minCoeff.cpp
-|   |   |   |   |-- PartialRedux_norm.cpp
-|   |   |   |   |-- PartialRedux_prod.cpp
-|   |   |   |   |-- PartialRedux_squaredNorm.cpp
-|   |   |   |   |-- PartialRedux_sum.cpp
-|   |   |   |   |-- RealQZ_compute.cpp
-|   |   |   |   |-- RealSchur_compute.cpp
-|   |   |   |   |-- RealSchur_RealSchur_MatrixType.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_compute_MatrixType2.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_compute_MatrixType.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_eigenvalues.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_eigenvectors.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_operatorInverseSqrt.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_operatorSqrt.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_SelfAdjointEigenSolver.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp
-|   |   |   |   |-- SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp
-|   |   |   |   |-- SelfAdjointView_eigenvalues.cpp
-|   |   |   |   |-- SelfAdjointView_operatorNorm.cpp
-|   |   |   |   |-- SparseMatrix_coeffs.cpp
-|   |   |   |   |-- TopicAliasing_block_correct.cpp
-|   |   |   |   |-- TopicAliasing_block.cpp
-|   |   |   |   |-- TopicAliasing_cwise.cpp
-|   |   |   |   |-- TopicAliasing_mult1.cpp
-|   |   |   |   |-- TopicAliasing_mult2.cpp
-|   |   |   |   |-- TopicAliasing_mult3.cpp
-|   |   |   |   |-- TopicAliasing_mult4.cpp
-|   |   |   |   |-- TopicAliasing_mult5.cpp
-|   |   |   |   |-- TopicStorageOrders_example.cpp
-|   |   |   |   |-- Triangular_solve.cpp
-|   |   |   |   |-- Tridiagonalization_compute.cpp
-|   |   |   |   |-- Tridiagonalization_decomposeInPlace.cpp
-|   |   |   |   |-- Tridiagonalization_diagonal.cpp
-|   |   |   |   |-- Tridiagonalization_householderCoefficients.cpp
-|   |   |   |   |-- Tridiagonalization_packedMatrix.cpp
-|   |   |   |   |-- Tridiagonalization_Tridiagonalization_MatrixType.cpp
-|   |   |   |   |-- tut_arithmetic_redux_minmax.cpp
-|   |   |   |   |-- tut_arithmetic_transpose_aliasing.cpp
-|   |   |   |   |-- tut_arithmetic_transpose_conjugate.cpp
-|   |   |   |   |-- tut_arithmetic_transpose_inplace.cpp
-|   |   |   |   |-- tut_matrix_assignment_resizing.cpp
-|   |   |   |   |-- Tutorial_AdvancedInitialization_Block.cpp
-|   |   |   |   |-- Tutorial_AdvancedInitialization_CommaTemporary.cpp
-|   |   |   |   |-- Tutorial_AdvancedInitialization_Join.cpp
-|   |   |   |   |-- Tutorial_AdvancedInitialization_LinSpaced.cpp
-|   |   |   |   |-- Tutorial_AdvancedInitialization_ThreeWays.cpp
-|   |   |   |   |-- Tutorial_AdvancedInitialization_Zero.cpp
-|   |   |   |   |-- Tutorial_commainit_01b.cpp
-|   |   |   |   |-- Tutorial_commainit_01.cpp
-|   |   |   |   |-- Tutorial_commainit_02.cpp
-|   |   |   |   |-- Tutorial_Map_rowmajor.cpp
-|   |   |   |   |-- Tutorial_Map_using.cpp
-|   |   |   |   |-- Tutorial_ReshapeMat2Mat.cpp
-|   |   |   |   |-- Tutorial_ReshapeMat2Vec.cpp
-|   |   |   |   |-- Tutorial_SlicingCol.cpp
-|   |   |   |   |-- Tutorial_SlicingVec.cpp
-|   |   |   |   |-- Tutorial_solve_matrix_inverse.cpp
-|   |   |   |   |-- Tutorial_solve_multiple_rhs.cpp
-|   |   |   |   |-- Tutorial_solve_reuse_decomposition.cpp
-|   |   |   |   |-- Tutorial_solve_singular.cpp
-|   |   |   |   |-- Tutorial_solve_triangular.cpp
-|   |   |   |   |-- Tutorial_solve_triangular_inplace.cpp
-|   |   |   |   |-- VectorwiseOp_homogeneous.cpp
-|   |   |   |   `-- Vectorwise_reverse.cpp
-|   |   |   |-- special_examples
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- random_cpp11.cpp
-|   |   |   |   |-- Tutorial_sparse_example.cpp
-|   |   |   |   `-- Tutorial_sparse_example_details.cpp
-|   |   |   |-- A05_PortingFrom2To3.dox
-|   |   |   |-- AsciiQuickReference.txt
-|   |   |   |-- B01_Experimental.dox
-|   |   |   |-- ClassHierarchy.dox
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- CoeffwiseMathFunctionsTable.dox
-|   |   |   |-- CustomizingEigen_CustomScalar.dox
-|   |   |   |-- CustomizingEigen_InheritingMatrix.dox
-|   |   |   |-- CustomizingEigen_NullaryExpr.dox
-|   |   |   |-- CustomizingEigen_Plugins.dox
-|   |   |   |-- DenseDecompositionBenchmark.dox
-|   |   |   |-- Doxyfile.in
-|   |   |   |-- eigendoxy.css
-|   |   |   |-- eigendoxy_footer.html.in
-|   |   |   |-- eigendoxy_header.html.in
-|   |   |   |-- eigendoxy_layout.xml.in
-|   |   |   |-- eigendoxy_tabs.css
-|   |   |   |-- eigen_navtree_hacks.js
-|   |   |   |-- Eigen_Silly_Professor_64x64.png
-|   |   |   |-- FixedSizeVectorizable.dox
-|   |   |   |-- ftv2node.png
-|   |   |   |-- ftv2pnode.png
-|   |   |   |-- FunctionsTakingEigenTypes.dox
-|   |   |   |-- HiPerformance.dox
-|   |   |   |-- InplaceDecomposition.dox
-|   |   |   |-- InsideEigenExample.dox
-|   |   |   |-- LeastSquares.dox
-|   |   |   |-- Manual.dox
-|   |   |   |-- MatrixfreeSolverExample.dox
-|   |   |   |-- NewExpressionType.dox
-|   |   |   |-- Overview.dox
-|   |   |   |-- PassingByValue.dox
-|   |   |   |-- Pitfalls.dox
-|   |   |   |-- PreprocessorDirectives.dox
-|   |   |   |-- QuickReference.dox
-|   |   |   |-- QuickStartGuide.dox
-|   |   |   |-- SparseLinearSystems.dox
-|   |   |   |-- SparseQuickReference.dox
-|   |   |   |-- StlContainers.dox
-|   |   |   |-- StorageOrders.dox
-|   |   |   |-- StructHavingEigenMembers.dox
-|   |   |   |-- TemplateKeyword.dox
-|   |   |   |-- TopicAliasing.dox
-|   |   |   |-- TopicAssertions.dox
-|   |   |   |-- TopicCMakeGuide.dox
-|   |   |   |-- TopicEigenExpressionTemplates.dox
-|   |   |   |-- TopicLazyEvaluation.dox
-|   |   |   |-- TopicLinearAlgebraDecompositions.dox
-|   |   |   |-- TopicMultithreading.dox
-|   |   |   |-- TopicResizing.dox
-|   |   |   |-- TopicScalarTypes.dox
-|   |   |   |-- TopicVectorization.dox
-|   |   |   |-- TutorialAdvancedInitialization.dox
-|   |   |   |-- TutorialArrayClass.dox
-|   |   |   |-- TutorialBlockOperations.dox
-|   |   |   |-- tutorial.cpp
-|   |   |   |-- TutorialGeometry.dox
-|   |   |   |-- TutorialLinearAlgebra.dox
-|   |   |   |-- TutorialMapClass.dox
-|   |   |   |-- TutorialMatrixArithmetic.dox
-|   |   |   |-- TutorialMatrixClass.dox
-|   |   |   |-- TutorialReductionsVisitorsBroadcasting.dox
-|   |   |   |-- TutorialReshapeSlicing.dox
-|   |   |   |-- TutorialSparse.dox
-|   |   |   |-- TutorialSparse_example_details.dox
-|   |   |   |-- UnalignedArrayAssert.dox
-|   |   |   |-- UsingBlasLapackBackends.dox
-|   |   |   |-- UsingIntelMKL.dox
-|   |   |   |-- UsingNVCC.dox
-|   |   |   `-- WrongStackAlignment.dox
-|   |   |-- Eigen
-|   |   |   |-- src
-|   |   |   |   |-- Cholesky
-|   |   |   |   |   |-- LDLT.h
-|   |   |   |   |   |-- LLT.h
-|   |   |   |   |   `-- LLT_LAPACKE.h
-|   |   |   |   |-- CholmodSupport
-|   |   |   |   |   `-- CholmodSupport.h
-|   |   |   |   |-- Core
-|   |   |   |   |   |-- arch
-|   |   |   |   |   |   |-- AltiVec
-|   |   |   |   |   |   |   |-- Complex.h
-|   |   |   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |   |   `-- PacketMath.h
-|   |   |   |   |   |   |-- AVX
-|   |   |   |   |   |   |   |-- Complex.h
-|   |   |   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |   |   |-- PacketMath.h
-|   |   |   |   |   |   |   `-- TypeCasting.h
-|   |   |   |   |   |   |-- AVX512
-|   |   |   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |   |   `-- PacketMath.h
-|   |   |   |   |   |   |-- CUDA
-|   |   |   |   |   |   |   |-- Complex.h
-|   |   |   |   |   |   |   |-- Half.h
-|   |   |   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |   |   |-- PacketMath.h
-|   |   |   |   |   |   |   |-- PacketMathHalf.h
-|   |   |   |   |   |   |   `-- TypeCasting.h
-|   |   |   |   |   |   |-- Default
-|   |   |   |   |   |   |   |-- ConjHelper.h
-|   |   |   |   |   |   |   `-- Settings.h
-|   |   |   |   |   |   |-- NEON
-|   |   |   |   |   |   |   |-- Complex.h
-|   |   |   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |   |   `-- PacketMath.h
-|   |   |   |   |   |   |-- SSE
-|   |   |   |   |   |   |   |-- Complex.h
-|   |   |   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |   |   |-- PacketMath.h
-|   |   |   |   |   |   |   `-- TypeCasting.h
-|   |   |   |   |   |   `-- ZVector
-|   |   |   |   |   |       |-- Complex.h
-|   |   |   |   |   |       |-- MathFunctions.h
-|   |   |   |   |   |       `-- PacketMath.h
-|   |   |   |   |   |-- functors
-|   |   |   |   |   |   |-- AssignmentFunctors.h
-|   |   |   |   |   |   |-- BinaryFunctors.h
-|   |   |   |   |   |   |-- NullaryFunctors.h
-|   |   |   |   |   |   |-- StlFunctors.h
-|   |   |   |   |   |   |-- TernaryFunctors.h
-|   |   |   |   |   |   `-- UnaryFunctors.h
-|   |   |   |   |   |-- products
-|   |   |   |   |   |   |-- GeneralBlockPanelKernel.h
-|   |   |   |   |   |   |-- GeneralMatrixMatrix_BLAS.h
-|   |   |   |   |   |   |-- GeneralMatrixMatrix.h
-|   |   |   |   |   |   |-- GeneralMatrixMatrixTriangular_BLAS.h
-|   |   |   |   |   |   |-- GeneralMatrixMatrixTriangular.h
-|   |   |   |   |   |   |-- GeneralMatrixVector_BLAS.h
-|   |   |   |   |   |   |-- GeneralMatrixVector.h
-|   |   |   |   |   |   |-- Parallelizer.h
-|   |   |   |   |   |   |-- SelfadjointMatrixMatrix_BLAS.h
-|   |   |   |   |   |   |-- SelfadjointMatrixMatrix.h
-|   |   |   |   |   |   |-- SelfadjointMatrixVector_BLAS.h
-|   |   |   |   |   |   |-- SelfadjointMatrixVector.h
-|   |   |   |   |   |   |-- SelfadjointProduct.h
-|   |   |   |   |   |   |-- SelfadjointRank2Update.h
-|   |   |   |   |   |   |-- TriangularMatrixMatrix_BLAS.h
-|   |   |   |   |   |   |-- TriangularMatrixMatrix.h
-|   |   |   |   |   |   |-- TriangularMatrixVector_BLAS.h
-|   |   |   |   |   |   |-- TriangularMatrixVector.h
-|   |   |   |   |   |   |-- TriangularSolverMatrix_BLAS.h
-|   |   |   |   |   |   |-- TriangularSolverMatrix.h
-|   |   |   |   |   |   `-- TriangularSolverVector.h
-|   |   |   |   |   |-- util
-|   |   |   |   |   |   |-- BlasUtil.h
-|   |   |   |   |   |   |-- Constants.h
-|   |   |   |   |   |   |-- DisableStupidWarnings.h
-|   |   |   |   |   |   |-- ForwardDeclarations.h
-|   |   |   |   |   |   |-- Macros.h
-|   |   |   |   |   |   |-- Memory.h
-|   |   |   |   |   |   |-- Meta.h
-|   |   |   |   |   |   |-- MKL_support.h
-|   |   |   |   |   |   |-- NonMPL2.h
-|   |   |   |   |   |   |-- ReenableStupidWarnings.h
-|   |   |   |   |   |   |-- StaticAssert.h
-|   |   |   |   |   |   `-- XprHelper.h
-|   |   |   |   |   |-- ArrayBase.h
-|   |   |   |   |   |-- Array.h
-|   |   |   |   |   |-- ArrayWrapper.h
-|   |   |   |   |   |-- AssignEvaluator.h
-|   |   |   |   |   |-- Assign.h
-|   |   |   |   |   |-- Assign_MKL.h
-|   |   |   |   |   |-- BandMatrix.h
-|   |   |   |   |   |-- Block.h
-|   |   |   |   |   |-- BooleanRedux.h
-|   |   |   |   |   |-- CommaInitializer.h
-|   |   |   |   |   |-- ConditionEstimator.h
-|   |   |   |   |   |-- CoreEvaluators.h
-|   |   |   |   |   |-- CoreIterators.h
-|   |   |   |   |   |-- CwiseBinaryOp.h
-|   |   |   |   |   |-- CwiseNullaryOp.h
-|   |   |   |   |   |-- CwiseTernaryOp.h
-|   |   |   |   |   |-- CwiseUnaryOp.h
-|   |   |   |   |   |-- CwiseUnaryView.h
-|   |   |   |   |   |-- DenseBase.h
-|   |   |   |   |   |-- DenseCoeffsBase.h
-|   |   |   |   |   |-- DenseStorage.h
-|   |   |   |   |   |-- Diagonal.h
-|   |   |   |   |   |-- DiagonalMatrix.h
-|   |   |   |   |   |-- DiagonalProduct.h
-|   |   |   |   |   |-- Dot.h
-|   |   |   |   |   |-- EigenBase.h
-|   |   |   |   |   |-- ForceAlignedAccess.h
-|   |   |   |   |   |-- Fuzzy.h
-|   |   |   |   |   |-- GeneralProduct.h
-|   |   |   |   |   |-- GenericPacketMath.h
-|   |   |   |   |   |-- GlobalFunctions.h
-|   |   |   |   |   |-- Inverse.h
-|   |   |   |   |   |-- IO.h
-|   |   |   |   |   |-- MapBase.h
-|   |   |   |   |   |-- Map.h
-|   |   |   |   |   |-- MathFunctions.h
-|   |   |   |   |   |-- MathFunctionsImpl.h
-|   |   |   |   |   |-- MatrixBase.h
-|   |   |   |   |   |-- Matrix.h
-|   |   |   |   |   |-- NestByValue.h
-|   |   |   |   |   |-- NoAlias.h
-|   |   |   |   |   |-- NumTraits.h
-|   |   |   |   |   |-- PermutationMatrix.h
-|   |   |   |   |   |-- PlainObjectBase.h
-|   |   |   |   |   |-- ProductEvaluators.h
-|   |   |   |   |   |-- Product.h
-|   |   |   |   |   |-- Random.h
-|   |   |   |   |   |-- Redux.h
-|   |   |   |   |   |-- Ref.h
-|   |   |   |   |   |-- Replicate.h
-|   |   |   |   |   |-- ReturnByValue.h
-|   |   |   |   |   |-- Reverse.h
-|   |   |   |   |   |-- Select.h
-|   |   |   |   |   |-- SelfAdjointView.h
-|   |   |   |   |   |-- SelfCwiseBinaryOp.h
-|   |   |   |   |   |-- Solve.h
-|   |   |   |   |   |-- SolverBase.h
-|   |   |   |   |   |-- SolveTriangular.h
-|   |   |   |   |   |-- StableNorm.h
-|   |   |   |   |   |-- Stride.h
-|   |   |   |   |   |-- Swap.h
-|   |   |   |   |   |-- Transpose.h
-|   |   |   |   |   |-- Transpositions.h
-|   |   |   |   |   |-- TriangularMatrix.h
-|   |   |   |   |   |-- VectorBlock.h
-|   |   |   |   |   |-- VectorwiseOp.h
-|   |   |   |   |   `-- Visitor.h
-|   |   |   |   |-- Eigenvalues
-|   |   |   |   |   |-- ComplexEigenSolver.h
-|   |   |   |   |   |-- ComplexSchur.h
-|   |   |   |   |   |-- ComplexSchur_LAPACKE.h
-|   |   |   |   |   |-- EigenSolver.h
-|   |   |   |   |   |-- GeneralizedEigenSolver.h
-|   |   |   |   |   |-- GeneralizedSelfAdjointEigenSolver.h
-|   |   |   |   |   |-- HessenbergDecomposition.h
-|   |   |   |   |   |-- MatrixBaseEigenvalues.h
-|   |   |   |   |   |-- RealQZ.h
-|   |   |   |   |   |-- RealSchur.h
-|   |   |   |   |   |-- RealSchur_LAPACKE.h
-|   |   |   |   |   |-- SelfAdjointEigenSolver.h
-|   |   |   |   |   |-- SelfAdjointEigenSolver_LAPACKE.h
-|   |   |   |   |   `-- Tridiagonalization.h
-|   |   |   |   |-- Geometry
-|   |   |   |   |   |-- arch
-|   |   |   |   |   |   `-- Geometry_SSE.h
-|   |   |   |   |   |-- AlignedBox.h
-|   |   |   |   |   |-- AngleAxis.h
-|   |   |   |   |   |-- EulerAngles.h
-|   |   |   |   |   |-- Homogeneous.h
-|   |   |   |   |   |-- Hyperplane.h
-|   |   |   |   |   |-- OrthoMethods.h
-|   |   |   |   |   |-- ParametrizedLine.h
-|   |   |   |   |   |-- Quaternion.h
-|   |   |   |   |   |-- Rotation2D.h
-|   |   |   |   |   |-- RotationBase.h
-|   |   |   |   |   |-- Scaling.h
-|   |   |   |   |   |-- Transform.h
-|   |   |   |   |   |-- Translation.h
-|   |   |   |   |   `-- Umeyama.h
-|   |   |   |   |-- Householder
-|   |   |   |   |   |-- BlockHouseholder.h
-|   |   |   |   |   |-- Householder.h
-|   |   |   |   |   `-- HouseholderSequence.h
-|   |   |   |   |-- IterativeLinearSolvers
-|   |   |   |   |   |-- BasicPreconditioners.h
-|   |   |   |   |   |-- BiCGSTAB.h
-|   |   |   |   |   |-- ConjugateGradient.h
-|   |   |   |   |   |-- IncompleteCholesky.h
-|   |   |   |   |   |-- IncompleteLUT.h
-|   |   |   |   |   |-- IterativeSolverBase.h
-|   |   |   |   |   |-- LeastSquareConjugateGradient.h
-|   |   |   |   |   `-- SolveWithGuess.h
-|   |   |   |   |-- Jacobi
-|   |   |   |   |   `-- Jacobi.h
-|   |   |   |   |-- LU
-|   |   |   |   |   |-- arch
-|   |   |   |   |   |   `-- Inverse_SSE.h
-|   |   |   |   |   |-- Determinant.h
-|   |   |   |   |   |-- FullPivLU.h
-|   |   |   |   |   |-- InverseImpl.h
-|   |   |   |   |   |-- PartialPivLU.h
-|   |   |   |   |   `-- PartialPivLU_LAPACKE.h
-|   |   |   |   |-- MetisSupport
-|   |   |   |   |   `-- MetisSupport.h
-|   |   |   |   |-- misc
-|   |   |   |   |   |-- blas.h
-|   |   |   |   |   |-- Image.h
-|   |   |   |   |   |-- Kernel.h
-|   |   |   |   |   |-- lapacke.h
-|   |   |   |   |   |-- lapacke_mangling.h
-|   |   |   |   |   |-- lapack.h
-|   |   |   |   |   `-- RealSvd2x2.h
-|   |   |   |   |-- OrderingMethods
-|   |   |   |   |   |-- Amd.h
-|   |   |   |   |   |-- Eigen_Colamd.h
-|   |   |   |   |   `-- Ordering.h
-|   |   |   |   |-- PardisoSupport
-|   |   |   |   |   `-- PardisoSupport.h
-|   |   |   |   |-- PaStiXSupport
-|   |   |   |   |   `-- PaStiXSupport.h
-|   |   |   |   |-- plugins
-|   |   |   |   |   |-- ArrayCwiseBinaryOps.h
-|   |   |   |   |   |-- ArrayCwiseUnaryOps.h
-|   |   |   |   |   |-- BlockMethods.h
-|   |   |   |   |   |-- CommonCwiseBinaryOps.h
-|   |   |   |   |   |-- CommonCwiseUnaryOps.h
-|   |   |   |   |   |-- MatrixCwiseBinaryOps.h
-|   |   |   |   |   `-- MatrixCwiseUnaryOps.h
-|   |   |   |   |-- QR
-|   |   |   |   |   |-- ColPivHouseholderQR.h
-|   |   |   |   |   |-- ColPivHouseholderQR_LAPACKE.h
-|   |   |   |   |   |-- CompleteOrthogonalDecomposition.h
-|   |   |   |   |   |-- FullPivHouseholderQR.h
-|   |   |   |   |   |-- HouseholderQR.h
-|   |   |   |   |   `-- HouseholderQR_LAPACKE.h
-|   |   |   |   |-- SparseCholesky
-|   |   |   |   |   |-- SimplicialCholesky.h
-|   |   |   |   |   `-- SimplicialCholesky_impl.h
-|   |   |   |   |-- SparseCore
-|   |   |   |   |   |-- AmbiVector.h
-|   |   |   |   |   |-- CompressedStorage.h
-|   |   |   |   |   |-- ConservativeSparseSparseProduct.h
-|   |   |   |   |   |-- MappedSparseMatrix.h
-|   |   |   |   |   |-- SparseAssign.h
-|   |   |   |   |   |-- SparseBlock.h
-|   |   |   |   |   |-- SparseColEtree.h
-|   |   |   |   |   |-- SparseCompressedBase.h
-|   |   |   |   |   |-- SparseCwiseBinaryOp.h
-|   |   |   |   |   |-- SparseCwiseUnaryOp.h
-|   |   |   |   |   |-- SparseDenseProduct.h
-|   |   |   |   |   |-- SparseDiagonalProduct.h
-|   |   |   |   |   |-- SparseDot.h
-|   |   |   |   |   |-- SparseFuzzy.h
-|   |   |   |   |   |-- SparseMap.h
-|   |   |   |   |   |-- SparseMatrixBase.h
-|   |   |   |   |   |-- SparseMatrix.h
-|   |   |   |   |   |-- SparsePermutation.h
-|   |   |   |   |   |-- SparseProduct.h
-|   |   |   |   |   |-- SparseRedux.h
-|   |   |   |   |   |-- SparseRef.h
-|   |   |   |   |   |-- SparseSelfAdjointView.h
-|   |   |   |   |   |-- SparseSolverBase.h
-|   |   |   |   |   |-- SparseSparseProductWithPruning.h
-|   |   |   |   |   |-- SparseTranspose.h
-|   |   |   |   |   |-- SparseTriangularView.h
-|   |   |   |   |   |-- SparseUtil.h
-|   |   |   |   |   |-- SparseVector.h
-|   |   |   |   |   |-- SparseView.h
-|   |   |   |   |   `-- TriangularSolver.h
-|   |   |   |   |-- SparseLU
-|   |   |   |   |   |-- SparseLU_column_bmod.h
-|   |   |   |   |   |-- SparseLU_column_dfs.h
-|   |   |   |   |   |-- SparseLU_copy_to_ucol.h
-|   |   |   |   |   |-- SparseLU_gemm_kernel.h
-|   |   |   |   |   |-- SparseLU.h
-|   |   |   |   |   |-- SparseLU_heap_relax_snode.h
-|   |   |   |   |   |-- SparseLUImpl.h
-|   |   |   |   |   |-- SparseLU_kernel_bmod.h
-|   |   |   |   |   |-- SparseLU_Memory.h
-|   |   |   |   |   |-- SparseLU_panel_bmod.h
-|   |   |   |   |   |-- SparseLU_panel_dfs.h
-|   |   |   |   |   |-- SparseLU_pivotL.h
-|   |   |   |   |   |-- SparseLU_pruneL.h
-|   |   |   |   |   |-- SparseLU_relax_snode.h
-|   |   |   |   |   |-- SparseLU_Structs.h
-|   |   |   |   |   |-- SparseLU_SupernodalMatrix.h
-|   |   |   |   |   `-- SparseLU_Utils.h
-|   |   |   |   |-- SparseQR
-|   |   |   |   |   `-- SparseQR.h
-|   |   |   |   |-- SPQRSupport
-|   |   |   |   |   `-- SuiteSparseQRSupport.h
-|   |   |   |   |-- StlSupport
-|   |   |   |   |   |-- details.h
-|   |   |   |   |   |-- StdDeque.h
-|   |   |   |   |   |-- StdList.h
-|   |   |   |   |   `-- StdVector.h
-|   |   |   |   |-- SuperLUSupport
-|   |   |   |   |   `-- SuperLUSupport.h
-|   |   |   |   |-- SVD
-|   |   |   |   |   |-- BDCSVD.h
-|   |   |   |   |   |-- JacobiSVD.h
-|   |   |   |   |   |-- JacobiSVD_LAPACKE.h
-|   |   |   |   |   |-- SVDBase.h
-|   |   |   |   |   `-- UpperBidiagonalization.h
-|   |   |   |   `-- UmfPackSupport
-|   |   |   |       `-- UmfPackSupport.h
-|   |   |   |-- Cholesky
-|   |   |   |-- CholmodSupport
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- Core
-|   |   |   |-- Dense
-|   |   |   |-- Eigen
-|   |   |   |-- Eigenvalues
-|   |   |   |-- Geometry
-|   |   |   |-- Householder
-|   |   |   |-- IterativeLinearSolvers
-|   |   |   |-- Jacobi
-|   |   |   |-- LU
-|   |   |   |-- MetisSupport
-|   |   |   |-- OrderingMethods
-|   |   |   |-- PardisoSupport
-|   |   |   |-- PaStiXSupport
-|   |   |   |-- QR
-|   |   |   |-- QtAlignedMalloc
-|   |   |   |-- Sparse
-|   |   |   |-- SparseCholesky
-|   |   |   |-- SparseCore
-|   |   |   |-- SparseLU
-|   |   |   |-- SparseQR
-|   |   |   |-- SPQRSupport
-|   |   |   |-- StdDeque
-|   |   |   |-- StdList
-|   |   |   |-- StdVector
-|   |   |   |-- SuperLUSupport
-|   |   |   |-- SVD
-|   |   |   `-- UmfPackSupport
-|   |   |-- failtest
-|   |   |   |-- bdcsvd_int.cpp
-|   |   |   |-- block_nonconst_ctor_on_const_xpr_0.cpp
-|   |   |   |-- block_nonconst_ctor_on_const_xpr_1.cpp
-|   |   |   |-- block_nonconst_ctor_on_const_xpr_2.cpp
-|   |   |   |-- block_on_const_type_actually_const_0.cpp
-|   |   |   |-- block_on_const_type_actually_const_1.cpp
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- colpivqr_int.cpp
-|   |   |   |-- const_qualified_block_method_retval_0.cpp
-|   |   |   |-- const_qualified_block_method_retval_1.cpp
-|   |   |   |-- const_qualified_diagonal_method_retval.cpp
-|   |   |   |-- const_qualified_transpose_method_retval.cpp
-|   |   |   |-- cwiseunaryview_nonconst_ctor_on_const_xpr.cpp
-|   |   |   |-- cwiseunaryview_on_const_type_actually_const.cpp
-|   |   |   |-- diagonal_nonconst_ctor_on_const_xpr.cpp
-|   |   |   |-- diagonal_on_const_type_actually_const.cpp
-|   |   |   |-- eigensolver_cplx.cpp
-|   |   |   |-- eigensolver_int.cpp
-|   |   |   |-- failtest_sanity_check.cpp
-|   |   |   |-- fullpivlu_int.cpp
-|   |   |   |-- fullpivqr_int.cpp
-|   |   |   |-- jacobisvd_int.cpp
-|   |   |   |-- ldlt_int.cpp
-|   |   |   |-- llt_int.cpp
-|   |   |   |-- map_nonconst_ctor_on_const_ptr_0.cpp
-|   |   |   |-- map_nonconst_ctor_on_const_ptr_1.cpp
-|   |   |   |-- map_nonconst_ctor_on_const_ptr_2.cpp
-|   |   |   |-- map_nonconst_ctor_on_const_ptr_3.cpp
-|   |   |   |-- map_nonconst_ctor_on_const_ptr_4.cpp
-|   |   |   |-- map_on_const_type_actually_const_0.cpp
-|   |   |   |-- map_on_const_type_actually_const_1.cpp
-|   |   |   |-- partialpivlu_int.cpp
-|   |   |   |-- qr_int.cpp
-|   |   |   |-- ref_1.cpp
-|   |   |   |-- ref_2.cpp
-|   |   |   |-- ref_3.cpp
-|   |   |   |-- ref_4.cpp
-|   |   |   |-- ref_5.cpp
-|   |   |   |-- selfadjointview_nonconst_ctor_on_const_xpr.cpp
-|   |   |   |-- selfadjointview_on_const_type_actually_const.cpp
-|   |   |   |-- sparse_ref_1.cpp
-|   |   |   |-- sparse_ref_2.cpp
-|   |   |   |-- sparse_ref_3.cpp
-|   |   |   |-- sparse_ref_4.cpp
-|   |   |   |-- sparse_ref_5.cpp
-|   |   |   |-- sparse_storage_mismatch.cpp
-|   |   |   |-- swap_1.cpp
-|   |   |   |-- swap_2.cpp
-|   |   |   |-- ternary_1.cpp
-|   |   |   |-- ternary_2.cpp
-|   |   |   |-- transpose_nonconst_ctor_on_const_xpr.cpp
-|   |   |   |-- transpose_on_const_type_actually_const.cpp
-|   |   |   |-- triangularview_nonconst_ctor_on_const_xpr.cpp
-|   |   |   `-- triangularview_on_const_type_actually_const.cpp
-|   |   |-- lapack
-|   |   |   |-- cholesky.cpp
-|   |   |   |-- clacgv.f
-|   |   |   |-- cladiv.f
-|   |   |   |-- clarfb.f
-|   |   |   |-- clarf.f
-|   |   |   |-- clarfg.f
-|   |   |   |-- clarft.f
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- complex_double.cpp
-|   |   |   |-- complex_single.cpp
-|   |   |   |-- dladiv.f
-|   |   |   |-- dlamch.f
-|   |   |   |-- dlapy2.f
-|   |   |   |-- dlapy3.f
-|   |   |   |-- dlarfb.f
-|   |   |   |-- dlarf.f
-|   |   |   |-- dlarfg.f
-|   |   |   |-- dlarft.f
-|   |   |   |-- double.cpp
-|   |   |   |-- dsecnd_NONE.f
-|   |   |   |-- eigenvalues.cpp
-|   |   |   |-- ilaclc.f
-|   |   |   |-- ilaclr.f
-|   |   |   |-- iladlc.f
-|   |   |   |-- iladlr.f
-|   |   |   |-- ilaslc.f
-|   |   |   |-- ilaslr.f
-|   |   |   |-- ilazlc.f
-|   |   |   |-- ilazlr.f
-|   |   |   |-- lapack_common.h
-|   |   |   |-- lu.cpp
-|   |   |   |-- second_NONE.f
-|   |   |   |-- single.cpp
-|   |   |   |-- sladiv.f
-|   |   |   |-- slamch.f
-|   |   |   |-- slapy2.f
-|   |   |   |-- slapy3.f
-|   |   |   |-- slarfb.f
-|   |   |   |-- slarf.f
-|   |   |   |-- slarfg.f
-|   |   |   |-- slarft.f
-|   |   |   |-- svd.cpp
-|   |   |   |-- zlacgv.f
-|   |   |   |-- zladiv.f
-|   |   |   |-- zlarfb.f
-|   |   |   |-- zlarf.f
-|   |   |   |-- zlarfg.f
-|   |   |   `-- zlarft.f
-|   |   |-- scripts
-|   |   |   |-- buildtests.in
-|   |   |   |-- cdashtesting.cmake.in
-|   |   |   |-- check.in
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- debug.in
-|   |   |   |-- eigen_gen_credits.cpp
-|   |   |   |-- eigen_gen_docs
-|   |   |   |-- release.in
-|   |   |   `-- relicense.py
-|   |   |-- test
-|   |   |   |-- adjoint.cpp
-|   |   |   |-- array.cpp
-|   |   |   |-- array_for_matrix.cpp
-|   |   |   |-- array_of_string.cpp
-|   |   |   |-- array_replicate.cpp
-|   |   |   |-- array_reverse.cpp
-|   |   |   |-- bandmatrix.cpp
-|   |   |   |-- basicstuff.cpp
-|   |   |   |-- bdcsvd.cpp
-|   |   |   |-- bicgstab.cpp
-|   |   |   |-- block.cpp
-|   |   |   |-- boostmultiprec.cpp
-|   |   |   |-- bug1213.cpp
-|   |   |   |-- bug1213.h
-|   |   |   |-- bug1213_main.cpp
-|   |   |   |-- cholesky.cpp
-|   |   |   |-- cholmod_support.cpp
-|   |   |   |-- CMakeLists.txt
-|   |   |   |-- commainitializer.cpp
-|   |   |   |-- conjugate_gradient.cpp
-|   |   |   |-- conservative_resize.cpp
-|   |   |   |-- constructor.cpp
-|   |   |   |-- corners.cpp
-|   |   |   |-- ctorleak.cpp
-|   |   |   |-- cuda_basic.cu
-|   |   |   |-- cuda_common.h
-|   |   |   |-- denseLM.cpp
-|   |   |   |-- dense_storage.cpp
-|   |   |   |-- determinant.cpp
-|   |   |   |-- diagonal.cpp
-|   |   |   |-- diagonalmatrices.cpp
-|   |   |   |-- dontalign.cpp
-|   |   |   |-- dynalloc.cpp
-|   |   |   |-- eigen2support.cpp
-|   |   |   |-- eigensolver_complex.cpp
-|   |   |   |-- eigensolver_generalized_real.cpp
-|   |   |   |-- eigensolver_generic.cpp
-|   |   |   |-- eigensolver_selfadjoint.cpp
-|   |   |   |-- evaluator_common.h
-|   |   |   |-- evaluators.cpp
-|   |   |   |-- exceptions.cpp
-|   |   |   |-- fastmath.cpp
-|   |   |   |-- first_aligned.cpp
-|   |   |   |-- geo_alignedbox.cpp
-|   |   |   |-- geo_eulerangles.cpp
-|   |   |   |-- geo_homogeneous.cpp
-|   |   |   |-- geo_hyperplane.cpp
-|   |   |   |-- geo_orthomethods.cpp
-|   |   |   |-- geo_parametrizedline.cpp
-|   |   |   |-- geo_quaternion.cpp
-|   |   |   |-- geo_transformations.cpp
-|   |   |   |-- half_float.cpp
-|   |   |   |-- hessenberg.cpp
-|   |   |   |-- householder.cpp
-|   |   |   |-- incomplete_cholesky.cpp
-|   |   |   |-- inplace_decomposition.cpp
-|   |   |   |-- integer_types.cpp
-|   |   |   |-- inverse.cpp
-|   |   |   |-- is_same_dense.cpp
-|   |   |   |-- jacobi.cpp
-|   |   |   |-- jacobisvd.cpp
-|   |   |   |-- linearstructure.cpp
-|   |   |   |-- lscg.cpp
-|   |   |   |-- lu.cpp
-|   |   |   |-- main.h
-|   |   |   |-- mapped_matrix.cpp
-|   |   |   |-- mapstaticmethods.cpp
-|   |   |   |-- mapstride.cpp
-|   |   |   |-- meta.cpp
-|   |   |   |-- metis_support.cpp
-|   |   |   |-- miscmatrices.cpp
-|   |   |   |-- mixingtypes.cpp
-|   |   |   |-- mpl2only.cpp
-|   |   |   |-- nesting_ops.cpp
-|   |   |   |-- nomalloc.cpp
-|   |   |   |-- nullary.cpp
-|   |   |   |-- numext.cpp
-|   |   |   |-- packetmath.cpp
-|   |   |   |-- pardiso_support.cpp
-|   |   |   |-- pastix_support.cpp
-|   |   |   |-- permutationmatrices.cpp
-|   |   |   |-- prec_inverse_4x4.cpp
-|   |   |   |-- product_extra.cpp
-|   |   |   |-- product.h
-|   |   |   |-- product_large.cpp
-|   |   |   |-- product_mmtr.cpp
-|   |   |   |-- product_notemporary.cpp
-|   |   |   |-- product_selfadjoint.cpp
-|   |   |   |-- product_small.cpp
-|   |   |   |-- product_symm.cpp
-|   |   |   |-- product_syrk.cpp
-|   |   |   |-- product_trmm.cpp
-|   |   |   |-- product_trmv.cpp
-|   |   |   |-- product_trsolve.cpp
-|   |   |   |-- qr_colpivoting.cpp
-|   |   |   |-- qr.cpp
-|   |   |   |-- qr_fullpivoting.cpp
-|   |   |   |-- qtvector.cpp
-|   |   |   |-- rand.cpp
-|   |   |   |-- real_qz.cpp
-|   |   |   |-- redux.cpp
-|   |   |   |-- ref.cpp
-|   |   |   |-- resize.cpp
-|   |   |   |-- rvalue_types.cpp
-|   |   |   |-- schur_complex.cpp
-|   |   |   |-- schur_real.cpp
-|   |   |   |-- selfadjoint.cpp
-|   |   |   |-- simplicial_cholesky.cpp
-|   |   |   |-- sizeof.cpp
-|   |   |   |-- sizeoverflow.cpp
-|   |   |   |-- smallvectors.cpp
-|   |   |   |-- sparse_basic.cpp
-|   |   |   |-- sparse_block.cpp
-|   |   |   |-- sparse.h
-|   |   |   |-- sparseLM.cpp
-|   |   |   |-- sparselu.cpp
-|   |   |   |-- sparse_permutations.cpp
-|   |   |   |-- sparse_product.cpp
-|   |   |   |-- sparseqr.cpp
-|   |   |   |-- sparse_ref.cpp
-|   |   |   |-- sparse_solver.h
-|   |   |   |-- sparse_solvers.cpp
-|   |   |   |-- sparse_vector.cpp
-|   |   |   |-- special_numbers.cpp
-|   |   |   |-- spqr_support.cpp
-|   |   |   |-- stable_norm.cpp
-|   |   |   |-- stddeque.cpp
-|   |   |   |-- stddeque_overload.cpp
-|   |   |   |-- stdlist.cpp
-|   |   |   |-- stdlist_overload.cpp
-|   |   |   |-- stdvector.cpp
-|   |   |   |-- stdvector_overload.cpp
-|   |   |   |-- superlu_support.cpp
-|   |   |   |-- svd_common.h
-|   |   |   |-- svd_fill.h
-|   |   |   |-- swap.cpp
-|   |   |   |-- triangular.cpp
-|   |   |   |-- umeyama.cpp
-|   |   |   |-- umfpack_support.cpp
-|   |   |   |-- unalignedassert.cpp
-|   |   |   |-- unalignedcount.cpp
-|   |   |   |-- upperbidiagonalization.cpp
-|   |   |   |-- vectorization_logic.cpp
-|   |   |   |-- vectorwiseop.cpp
-|   |   |   |-- visitor.cpp
-|   |   |   `-- zerosized.cpp
-|   |   |-- unsupported
-|   |   |   |-- bench
-|   |   |   |   `-- bench_svd.cpp
-|   |   |   |-- doc
-|   |   |   |   |-- examples
-|   |   |   |   |   |-- BVH_Example.cpp
-|   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |-- EulerAngles.cpp
-|   |   |   |   |   |-- FFT.cpp
-|   |   |   |   |   |-- MatrixExponential.cpp
-|   |   |   |   |   |-- MatrixFunction.cpp
-|   |   |   |   |   |-- MatrixLogarithm.cpp
-|   |   |   |   |   |-- MatrixPower.cpp
-|   |   |   |   |   |-- MatrixPower_optimal.cpp
-|   |   |   |   |   |-- MatrixSine.cpp
-|   |   |   |   |   |-- MatrixSinh.cpp
-|   |   |   |   |   |-- MatrixSquareRoot.cpp
-|   |   |   |   |   |-- PolynomialSolver1.cpp
-|   |   |   |   |   `-- PolynomialUtils1.cpp
-|   |   |   |   |-- snippets
-|   |   |   |   |   `-- CMakeLists.txt
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- eigendoxy_layout.xml.in
-|   |   |   |   `-- Overview.dox
-|   |   |   |-- Eigen
-|   |   |   |   |-- CXX11
-|   |   |   |   |   |-- src
-|   |   |   |   |   |   |-- Tensor
-|   |   |   |   |   |   |   |-- README.md
-|   |   |   |   |   |   |   |-- TensorArgMax.h
-|   |   |   |   |   |   |   |-- TensorAssign.h
-|   |   |   |   |   |   |   |-- TensorBase.h
-|   |   |   |   |   |   |   |-- TensorBroadcasting.h
-|   |   |   |   |   |   |   |-- TensorChipping.h
-|   |   |   |   |   |   |   |-- TensorConcatenation.h
-|   |   |   |   |   |   |   |-- TensorContractionBlocking.h
-|   |   |   |   |   |   |   |-- TensorContractionCuda.h
-|   |   |   |   |   |   |   |-- TensorContraction.h
-|   |   |   |   |   |   |   |-- TensorContractionMapper.h
-|   |   |   |   |   |   |   |-- TensorContractionThreadPool.h
-|   |   |   |   |   |   |   |-- TensorConversion.h
-|   |   |   |   |   |   |   |-- TensorConvolution.h
-|   |   |   |   |   |   |   |-- TensorCostModel.h
-|   |   |   |   |   |   |   |-- TensorCustomOp.h
-|   |   |   |   |   |   |   |-- TensorDeviceCuda.h
-|   |   |   |   |   |   |   |-- TensorDeviceDefault.h
-|   |   |   |   |   |   |   |-- TensorDevice.h
-|   |   |   |   |   |   |   |-- TensorDeviceSycl.h
-|   |   |   |   |   |   |   |-- TensorDeviceThreadPool.h
-|   |   |   |   |   |   |   |-- TensorDimensionList.h
-|   |   |   |   |   |   |   |-- TensorDimensions.h
-|   |   |   |   |   |   |   |-- TensorEvalTo.h
-|   |   |   |   |   |   |   |-- TensorEvaluator.h
-|   |   |   |   |   |   |   |-- TensorExecutor.h
-|   |   |   |   |   |   |   |-- TensorExpr.h
-|   |   |   |   |   |   |   |-- TensorFFT.h
-|   |   |   |   |   |   |   |-- TensorFixedSize.h
-|   |   |   |   |   |   |   |-- TensorForcedEval.h
-|   |   |   |   |   |   |   |-- TensorForwardDeclarations.h
-|   |   |   |   |   |   |   |-- TensorFunctors.h
-|   |   |   |   |   |   |   |-- TensorGenerator.h
-|   |   |   |   |   |   |   |-- TensorGlobalFunctions.h
-|   |   |   |   |   |   |   |-- Tensor.h
-|   |   |   |   |   |   |   |-- TensorImagePatch.h
-|   |   |   |   |   |   |   |-- TensorIndexList.h
-|   |   |   |   |   |   |   |-- TensorInflation.h
-|   |   |   |   |   |   |   |-- TensorInitializer.h
-|   |   |   |   |   |   |   |-- TensorIntDiv.h
-|   |   |   |   |   |   |   |-- TensorIO.h
-|   |   |   |   |   |   |   |-- TensorLayoutSwap.h
-|   |   |   |   |   |   |   |-- TensorMacros.h
-|   |   |   |   |   |   |   |-- TensorMap.h
-|   |   |   |   |   |   |   |-- TensorMeta.h
-|   |   |   |   |   |   |   |-- TensorMorphing.h
-|   |   |   |   |   |   |   |-- TensorPadding.h
-|   |   |   |   |   |   |   |-- TensorPatch.h
-|   |   |   |   |   |   |   |-- TensorRandom.h
-|   |   |   |   |   |   |   |-- TensorReductionCuda.h
-|   |   |   |   |   |   |   |-- TensorReduction.h
-|   |   |   |   |   |   |   |-- TensorReductionSycl.h
-|   |   |   |   |   |   |   |-- TensorRef.h
-|   |   |   |   |   |   |   |-- TensorReverse.h
-|   |   |   |   |   |   |   |-- TensorScan.h
-|   |   |   |   |   |   |   |-- TensorShuffling.h
-|   |   |   |   |   |   |   |-- TensorStorage.h
-|   |   |   |   |   |   |   |-- TensorStriding.h
-|   |   |   |   |   |   |   |-- TensorSyclConvertToDeviceExpression.h
-|   |   |   |   |   |   |   |-- TensorSyclExprConstructor.h
-|   |   |   |   |   |   |   |-- TensorSyclExtractAccessor.h
-|   |   |   |   |   |   |   |-- TensorSyclExtractFunctors.h
-|   |   |   |   |   |   |   |-- TensorSycl.h
-|   |   |   |   |   |   |   |-- TensorSyclLeafCount.h
-|   |   |   |   |   |   |   |-- TensorSyclPlaceHolderExpr.h
-|   |   |   |   |   |   |   |-- TensorSyclRun.h
-|   |   |   |   |   |   |   |-- TensorSyclTuple.h
-|   |   |   |   |   |   |   |-- TensorTraits.h
-|   |   |   |   |   |   |   |-- TensorUInt128.h
-|   |   |   |   |   |   |   `-- TensorVolumePatch.h
-|   |   |   |   |   |   |-- TensorSymmetry
-|   |   |   |   |   |   |   |-- util
-|   |   |   |   |   |   |   |   `-- TemplateGroupTheory.h
-|   |   |   |   |   |   |   |-- DynamicSymmetry.h
-|   |   |   |   |   |   |   |-- StaticSymmetry.h
-|   |   |   |   |   |   |   `-- Symmetry.h
-|   |   |   |   |   |   |-- ThreadPool
-|   |   |   |   |   |   |   |-- EventCount.h
-|   |   |   |   |   |   |   |-- NonBlockingThreadPool.h
-|   |   |   |   |   |   |   |-- RunQueue.h
-|   |   |   |   |   |   |   |-- SimpleThreadPool.h
-|   |   |   |   |   |   |   |-- ThreadEnvironment.h
-|   |   |   |   |   |   |   |-- ThreadLocal.h
-|   |   |   |   |   |   |   |-- ThreadPoolInterface.h
-|   |   |   |   |   |   |   `-- ThreadYield.h
-|   |   |   |   |   |   `-- util
-|   |   |   |   |   |       |-- CXX11Meta.h
-|   |   |   |   |   |       |-- CXX11Workarounds.h
-|   |   |   |   |   |       |-- EmulateArray.h
-|   |   |   |   |   |       |-- EmulateCXX11Meta.h
-|   |   |   |   |   |       `-- MaxSizeVector.h
-|   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |-- Tensor
-|   |   |   |   |   |-- TensorSymmetry
-|   |   |   |   |   `-- ThreadPool
-|   |   |   |   |-- src
-|   |   |   |   |   |-- AutoDiff
-|   |   |   |   |   |   |-- AutoDiffJacobian.h
-|   |   |   |   |   |   |-- AutoDiffScalar.h
-|   |   |   |   |   |   `-- AutoDiffVector.h
-|   |   |   |   |   |-- BVH
-|   |   |   |   |   |   |-- BVAlgorithms.h
-|   |   |   |   |   |   `-- KdBVH.h
-|   |   |   |   |   |-- Eigenvalues
-|   |   |   |   |   |   `-- ArpackSelfAdjointEigenSolver.h
-|   |   |   |   |   |-- EulerAngles
-|   |   |   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |   |   |-- EulerAngles.h
-|   |   |   |   |   |   `-- EulerSystem.h
-|   |   |   |   |   |-- FFT
-|   |   |   |   |   |   |-- ei_fftw_impl.h
-|   |   |   |   |   |   `-- ei_kissfft_impl.h
-|   |   |   |   |   |-- IterativeSolvers
-|   |   |   |   |   |   |-- ConstrainedConjGrad.h
-|   |   |   |   |   |   |-- DGMRES.h
-|   |   |   |   |   |   |-- GMRES.h
-|   |   |   |   |   |   |-- IncompleteLU.h
-|   |   |   |   |   |   |-- IterationController.h
-|   |   |   |   |   |   |-- MINRES.h
-|   |   |   |   |   |   `-- Scaling.h
-|   |   |   |   |   |-- KroneckerProduct
-|   |   |   |   |   |   `-- KroneckerTensorProduct.h
-|   |   |   |   |   |-- LevenbergMarquardt
-|   |   |   |   |   |   |-- CopyrightMINPACK.txt
-|   |   |   |   |   |   |-- LevenbergMarquardt.h
-|   |   |   |   |   |   |-- LMcovar.h
-|   |   |   |   |   |   |-- LMonestep.h
-|   |   |   |   |   |   |-- LMpar.h
-|   |   |   |   |   |   `-- LMqrsolv.h
-|   |   |   |   |   |-- MatrixFunctions
-|   |   |   |   |   |   |-- MatrixExponential.h
-|   |   |   |   |   |   |-- MatrixFunction.h
-|   |   |   |   |   |   |-- MatrixLogarithm.h
-|   |   |   |   |   |   |-- MatrixPower.h
-|   |   |   |   |   |   |-- MatrixSquareRoot.h
-|   |   |   |   |   |   `-- StemFunction.h
-|   |   |   |   |   |-- MoreVectorization
-|   |   |   |   |   |   `-- MathFunctions.h
-|   |   |   |   |   |-- NonLinearOptimization
-|   |   |   |   |   |   |-- chkder.h
-|   |   |   |   |   |   |-- covar.h
-|   |   |   |   |   |   |-- dogleg.h
-|   |   |   |   |   |   |-- fdjac1.h
-|   |   |   |   |   |   |-- HybridNonLinearSolver.h
-|   |   |   |   |   |   |-- LevenbergMarquardt.h
-|   |   |   |   |   |   |-- lmpar.h
-|   |   |   |   |   |   |-- qrsolv.h
-|   |   |   |   |   |   |-- r1mpyq.h
-|   |   |   |   |   |   |-- r1updt.h
-|   |   |   |   |   |   `-- rwupdt.h
-|   |   |   |   |   |-- NumericalDiff
-|   |   |   |   |   |   `-- NumericalDiff.h
-|   |   |   |   |   |-- Polynomials
-|   |   |   |   |   |   |-- Companion.h
-|   |   |   |   |   |   |-- PolynomialSolver.h
-|   |   |   |   |   |   `-- PolynomialUtils.h
-|   |   |   |   |   |-- Skyline
-|   |   |   |   |   |   |-- SkylineInplaceLU.h
-|   |   |   |   |   |   |-- SkylineMatrixBase.h
-|   |   |   |   |   |   |-- SkylineMatrix.h
-|   |   |   |   |   |   |-- SkylineProduct.h
-|   |   |   |   |   |   |-- SkylineStorage.h
-|   |   |   |   |   |   `-- SkylineUtil.h
-|   |   |   |   |   |-- SparseExtra
-|   |   |   |   |   |   |-- BlockOfDynamicSparseMatrix.h
-|   |   |   |   |   |   |-- BlockSparseMatrix.h
-|   |   |   |   |   |   |-- DynamicSparseMatrix.h
-|   |   |   |   |   |   |-- MarketIO.h
-|   |   |   |   |   |   |-- MatrixMarketIterator.h
-|   |   |   |   |   |   `-- RandomSetter.h
-|   |   |   |   |   |-- SpecialFunctions
-|   |   |   |   |   |   |-- arch
-|   |   |   |   |   |   |   `-- CUDA
-|   |   |   |   |   |   |       `-- CudaSpecialFunctions.h
-|   |   |   |   |   |   |-- SpecialFunctionsArrayAPI.h
-|   |   |   |   |   |   |-- SpecialFunctionsFunctors.h
-|   |   |   |   |   |   |-- SpecialFunctionsHalf.h
-|   |   |   |   |   |   |-- SpecialFunctionsImpl.h
-|   |   |   |   |   |   `-- SpecialFunctionsPacketMath.h
-|   |   |   |   |   `-- Splines
-|   |   |   |   |       |-- SplineFitting.h
-|   |   |   |   |       |-- SplineFwd.h
-|   |   |   |   |       `-- Spline.h
-|   |   |   |   |-- AdolcForward
-|   |   |   |   |-- AlignedVector3
-|   |   |   |   |-- ArpackSupport
-|   |   |   |   |-- AutoDiff
-|   |   |   |   |-- BVH
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- EulerAngles
-|   |   |   |   |-- FFT
-|   |   |   |   |-- IterativeSolvers
-|   |   |   |   |-- KroneckerProduct
-|   |   |   |   |-- LevenbergMarquardt
-|   |   |   |   |-- MatrixFunctions
-|   |   |   |   |-- MoreVectorization
-|   |   |   |   |-- MPRealSupport
-|   |   |   |   |-- NonLinearOptimization
-|   |   |   |   |-- NumericalDiff
-|   |   |   |   |-- OpenGLSupport
-|   |   |   |   |-- Polynomials
-|   |   |   |   |-- Skyline
-|   |   |   |   |-- SparseExtra
-|   |   |   |   |-- SpecialFunctions
-|   |   |   |   `-- Splines
-|   |   |   |-- test
-|   |   |   |   |-- mpreal
-|   |   |   |   |   `-- mpreal.h
-|   |   |   |   |-- alignedvector3.cpp
-|   |   |   |   |-- autodiff.cpp
-|   |   |   |   |-- autodiff_scalar.cpp
-|   |   |   |   |-- BVH.cpp
-|   |   |   |   |-- CMakeLists.txt
-|   |   |   |   |-- cxx11_eventcount.cpp
-|   |   |   |   |-- cxx11_meta.cpp
-|   |   |   |   |-- cxx11_non_blocking_thread_pool.cpp
-|   |   |   |   |-- cxx11_runqueue.cpp
-|   |   |   |   |-- cxx11_tensor_argmax.cpp
-|   |   |   |   |-- cxx11_tensor_argmax_cuda.cu
-|   |   |   |   |-- cxx11_tensor_assign.cpp
-|   |   |   |   |-- cxx11_tensor_broadcasting.cpp
-|   |   |   |   |-- cxx11_tensor_broadcast_sycl.cpp
-|   |   |   |   |-- cxx11_tensor_cast_float16_cuda.cu
-|   |   |   |   |-- cxx11_tensor_casts.cpp
-|   |   |   |   |-- cxx11_tensor_chipping.cpp
-|   |   |   |   |-- cxx11_tensor_comparisons.cpp
-|   |   |   |   |-- cxx11_tensor_complex_cuda.cu
-|   |   |   |   |-- cxx11_tensor_complex_cwise_ops_cuda.cu
-|   |   |   |   |-- cxx11_tensor_concatenation.cpp
-|   |   |   |   |-- cxx11_tensor_const.cpp
-|   |   |   |   |-- cxx11_tensor_contract_cuda.cu
-|   |   |   |   |-- cxx11_tensor_contraction.cpp
-|   |   |   |   |-- cxx11_tensor_convolution.cpp
-|   |   |   |   |-- cxx11_tensor_cuda.cu
-|   |   |   |   |-- cxx11_tensor_custom_index.cpp
-|   |   |   |   |-- cxx11_tensor_custom_op.cpp
-|   |   |   |   |-- cxx11_tensor_device.cu
-|   |   |   |   |-- cxx11_tensor_device_sycl.cpp
-|   |   |   |   |-- cxx11_tensor_dimension.cpp
-|   |   |   |   |-- cxx11_tensor_empty.cpp
-|   |   |   |   |-- cxx11_tensor_expr.cpp
-|   |   |   |   |-- cxx11_tensor_fft.cpp
-|   |   |   |   |-- cxx11_tensor_fixed_size.cpp
-|   |   |   |   |-- cxx11_tensor_forced_eval.cpp
-|   |   |   |   |-- cxx11_tensor_forced_eval_sycl.cpp
-|   |   |   |   |-- cxx11_tensor_generator.cpp
-|   |   |   |   |-- cxx11_tensor_ifft.cpp
-|   |   |   |   |-- cxx11_tensor_image_patch.cpp
-|   |   |   |   |-- cxx11_tensor_index_list.cpp
-|   |   |   |   |-- cxx11_tensor_inflation.cpp
-|   |   |   |   |-- cxx11_tensor_intdiv.cpp
-|   |   |   |   |-- cxx11_tensor_io.cpp
-|   |   |   |   |-- cxx11_tensor_layout_swap.cpp
-|   |   |   |   |-- cxx11_tensor_lvalue.cpp
-|   |   |   |   |-- cxx11_tensor_map.cpp
-|   |   |   |   |-- cxx11_tensor_math.cpp
-|   |   |   |   |-- cxx11_tensor_mixed_indices.cpp
-|   |   |   |   |-- cxx11_tensor_morphing.cpp
-|   |   |   |   |-- cxx11_tensor_notification.cpp
-|   |   |   |   |-- cxx11_tensor_of_complex.cpp
-|   |   |   |   |-- cxx11_tensor_of_const_values.cpp
-|   |   |   |   |-- cxx11_tensor_of_float16_cuda.cu
-|   |   |   |   |-- cxx11_tensor_of_strings.cpp
-|   |   |   |   |-- cxx11_tensor_padding.cpp
-|   |   |   |   |-- cxx11_tensor_patch.cpp
-|   |   |   |   |-- cxx11_tensor_random.cpp
-|   |   |   |   |-- cxx11_tensor_random_cuda.cu
-|   |   |   |   |-- cxx11_tensor_reduction.cpp
-|   |   |   |   |-- cxx11_tensor_reduction_cuda.cu
-|   |   |   |   |-- cxx11_tensor_reduction_sycl.cpp
-|   |   |   |   |-- cxx11_tensor_ref.cpp
-|   |   |   |   |-- cxx11_tensor_reverse.cpp
-|   |   |   |   |-- cxx11_tensor_roundings.cpp
-|   |   |   |   |-- cxx11_tensor_scan.cpp
-|   |   |   |   |-- cxx11_tensor_scan_cuda.cu
-|   |   |   |   |-- cxx11_tensor_shuffling.cpp
-|   |   |   |   |-- cxx11_tensor_simple.cpp
-|   |   |   |   |-- cxx11_tensor_striding.cpp
-|   |   |   |   |-- cxx11_tensor_sugar.cpp
-|   |   |   |   |-- cxx11_tensor_sycl.cpp
-|   |   |   |   |-- cxx11_tensor_symmetry.cpp
-|   |   |   |   |-- cxx11_tensor_thread_pool.cpp
-|   |   |   |   |-- cxx11_tensor_uint128.cpp
-|   |   |   |   |-- cxx11_tensor_volume_patch.cpp
-|   |   |   |   |-- dgmres.cpp
-|   |   |   |   |-- EulerAngles.cpp
-|   |   |   |   |-- FFT.cpp
-|   |   |   |   |-- FFTW.cpp
-|   |   |   |   |-- forward_adolc.cpp
-|   |   |   |   |-- gmres.cpp
-|   |   |   |   |-- kronecker_product.cpp
-|   |   |   |   |-- levenberg_marquardt.cpp
-|   |   |   |   |-- matrix_exponential.cpp
-|   |   |   |   |-- matrix_function.cpp
-|   |   |   |   |-- matrix_functions.h
-|   |   |   |   |-- matrix_power.cpp
-|   |   |   |   |-- matrix_square_root.cpp
-|   |   |   |   |-- minres.cpp
-|   |   |   |   |-- mpreal_support.cpp
-|   |   |   |   |-- NonLinearOptimization.cpp
-|   |   |   |   |-- NumericalDiff.cpp
-|   |   |   |   |-- openglsupport.cpp
-|   |   |   |   |-- polynomialsolver.cpp
-|   |   |   |   |-- polynomialutils.cpp
-|   |   |   |   |-- sparse_extra.cpp
-|   |   |   |   |-- special_functions.cpp
-|   |   |   |   `-- splines.cpp
-|   |   |   |-- CMakeLists.txt
-|   |   |   `-- README.txt
-|   |   |-- CMakeLists.txt
-|   |   |-- COPYING.BSD
-|   |   |-- COPYING.GPL
-|   |   |-- COPYING.LGPL
-|   |   |-- COPYING.MINPACK
-|   |   |-- COPYING.MPL2
-|   |   |-- COPYING.README
-|   |   |-- CTestConfig.cmake
-|   |   |-- CTestCustom.cmake.in
-|   |   |-- eigen3.pc.in
-|   |   |-- INSTALL
-|   |   |-- README.md
-|   |   `-- signature_of_eigen3_matrix_library
-|   |-- lcov
-|   |   |-- bin
-|   |   |   |-- copy_dates.sh
-|   |   |   |-- gendesc
-|   |   |   |-- genhtml
-|   |   |   |-- geninfo
-|   |   |   |-- genpng
-|   |   |   |-- get_changes.sh
-|   |   |   |-- get_version.sh
-|   |   |   |-- install.sh
-|   |   |   |-- lcov
-|   |   |   `-- updateversion.pl
-|   |   |-- example
-|   |   |   |-- methods
-|   |   |   |   |-- gauss.c
-|   |   |   |   `-- iterate.c
-|   |   |   |-- descriptions.txt
-|   |   |   |-- example.c
-|   |   |   |-- gauss.h
-|   |   |   |-- iterate.h
-|   |   |   |-- Makefile
-|   |   |   `-- README
-|   |   |-- man
-|   |   |   |-- gendesc.1
-|   |   |   |-- genhtml.1
-|   |   |   |-- geninfo.1
-|   |   |   |-- genpng.1
-|   |   |   |-- lcov.1
-|   |   |   `-- lcovrc.5
-|   |   |-- rpm
-|   |   |   `-- lcov.spec
-|   |   |-- test
-|   |   |   |-- bin
-|   |   |   |   |-- common
-|   |   |   |   |-- mkinfo
-|   |   |   |   |-- norminfo
-|   |   |   |   |-- test_run
-|   |   |   |   |-- test_skip
-|   |   |   |   |-- testsuite_exit
-|   |   |   |   `-- testsuite_init
-|   |   |   |-- genhtml_output
-|   |   |   |   |-- genhtml_test
-|   |   |   |   `-- Makefile
-|   |   |   |-- lcov_add_files
-|   |   |   |   |-- add_test
-|   |   |   |   `-- Makefile
-|   |   |   |-- lcov_diff
-|   |   |   |   |-- new
-|   |   |   |   |   |-- Makefile
-|   |   |   |   |   `-- prog.c
-|   |   |   |   |-- old
-|   |   |   |   |   |-- Makefile
-|   |   |   |   |   `-- prog.c
-|   |   |   |   |-- diff_test
-|   |   |   |   `-- Makefile
-|   |   |   |-- lcov_misc
-|   |   |   |   `-- Makefile
-|   |   |   |-- lcov_summary
-|   |   |   |   |-- check_counts
-|   |   |   |   `-- Makefile
-|   |   |   |-- profiles
-|   |   |   |   |-- large
-|   |   |   |   |-- medium
-|   |   |   |   `-- small
-|   |   |   |-- common.mak
-|   |   |   |-- lcovrc
-|   |   |   `-- Makefile
-|   |   |-- CHANGES
-|   |   |-- CONTRIBUTING
-|   |   |-- COPYING
-|   |   |-- lcovrc
-|   |   |-- Makefile
-|   |   `-- README
-|   |-- phys
-|   |   `-- units
-|   |       |-- io.hpp
-|   |       |-- io_output_eng.hpp
-|   |       |-- io_output.hpp
-|   |       |-- io_symbols.hpp
-|   |       |-- other_units.hpp
-|   |       |-- physical_constants.hpp
-|   |       |-- quantity.hpp
-|   |       |-- quantity_io_ampere.hpp
-|   |       |-- quantity_io_becquerel.hpp
-|   |       |-- quantity_io_candela.hpp
-|   |       |-- quantity_io_celsius.hpp
-|   |       |-- quantity_io_coulomb.hpp
-|   |       |-- quantity_io_dimensionless.hpp
-|   |       |-- quantity_io_engineering.hpp
-|   |       |-- quantity_io_farad.hpp
-|   |       |-- quantity_io_gray.hpp
-|   |       |-- quantity_io_henry.hpp
-|   |       |-- quantity_io_hertz.hpp
-|   |       |-- quantity_io.hpp
-|   |       |-- quantity_io_joule.hpp
-|   |       |-- quantity_io_kelvin.hpp
-|   |       |-- quantity_io_kilogram.hpp
-|   |       |-- quantity_io_lumen.hpp
-|   |       |-- quantity_io_lux.hpp
-|   |       |-- quantity_io_meter.hpp
-|   |       |-- quantity_io_mole.hpp
-|   |       |-- quantity_io_newton.hpp
-|   |       |-- quantity_io_ohm.hpp
-|   |       |-- quantity_io_pascal.hpp
-|   |       |-- quantity_io_radian.hpp
-|   |       |-- quantity_io_second.hpp
-|   |       |-- quantity_io_siemens.hpp
-|   |       |-- quantity_io_sievert.hpp
-|   |       |-- quantity_io_speed.hpp
-|   |       |-- quantity_io_steradian.hpp
-|   |       |-- quantity_io_symbols.hpp
-|   |       |-- quantity_io_tesla.hpp
-|   |       |-- quantity_io_volt.hpp
-|   |       |-- quantity_io_watt.hpp
-|   |       `-- quantity_io_weber.hpp
-|   |-- CMakeLists.txt
-|   |-- eigen-eigen-b3f3d4950030.tar.bz2
-|   |-- pythia8235.tar.bz2
-|   `-- ThirdParty.dox
-|-- Tools
-|   |-- CMakeLists.txt
-|   |-- plot_crossings.sh
-|   `-- plot_tracks.sh
-|-- AUTHORS
-|-- CHANGELOG
-|-- CMakeLists.txt
-|-- COLLABORATION_AGREEMENT.md
-|-- CONTRIBUTING.md
-|-- corsika.dox
-|-- do-clang-format.py
-|-- do-copyright.py
-|-- FIXME.md
-|-- LICENSE
-|-- MCNET_GUIDELINES
-|-- README.md
-`-- SCIENTIFIC_AUTHORS
-```
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
index 85e3786be3061bba45a7e4814bd69c0ce765e300..a57e4bfbbbff4526527819a3f2e4840c58a9b799 100644
--- a/MAINTAINERS.md
+++ b/MAINTAINERS.md
@@ -1,23 +1,25 @@
+
 Maintainers of the CORSIKA8 project are collaborators actively taking
 care of code contributions, quality control, development, and related
 discussions. 
 
-General:
+General and infrastructure:
 - Ralf Ulrich <ralf.ulrich@kit.edu>, KIT
 - Maximilian Reininghaus <maximilian.reininghaus@kit.edu>, KIT
 - Hans Dembinski <hdembins@mpi-hd.mpg.de>, Dortmund
+- Antonio Augusto Alves Junior <antonio.junior@kit.edu>, KIT
 
 High performance, GPU: 
 - Dominik Baack <dominik.baack@tu-dortmund.de>, Dortmund
 - Antonio Augusto Alves Junior <antonio.junior@kit.edu>, KIT
 - Luisa Arrabito <arrabito@in2p3.fr>, Montpellier
 
-Electromagnetic models, and infrastructure: 
+Electromagnetic models: 
 - Jean-Marco Alameddine <jean-marco.alameddine@udo.edu>, Dortmund
 - Jan Soedingrekso <jan.soedingrekso@tu-dortmund.de>, Dortmund
 - Maximilian Sackel <maximilian.sackel@udo.edu>, Dortmund
 
-Hadron models and infrastructure:
+Hadron models:
 - Felix Riehn <friehn@lip.pt>, Santiago/Lisbon
 - Anatoli Fedynitch <anatoli.fedynitch@icecube.wisc.edu> ICRR Tokyo
 
diff --git a/cmake/CorsikaUtilities.cmake b/cmake/CorsikaUtilities.cmake
index 96d29eeb614391ae0f4fd05a4892e7d02eeeef2d..2e620290419bd2353092c18237e98aa0a15c4f04 100644
--- a/cmake/CorsikaUtilities.cmake
+++ b/cmake/CorsikaUtilities.cmake
@@ -8,92 +8,6 @@
 # the license.
 #
 
-#################################################
-#
-# takes a list of input files and prepends a path
-#
-
-function (CORSIKA_PREPEND_PATH return prefix)
-  set (listVar "")
-  foreach (f ${ARGN})
-    list (APPEND listVar "${prefix}/${f}")
-  endforeach (f)
-  set (${return} "${listVar}" PARENT_SCOPE)
-endfunction (CORSIKA_PREPEND_PATH)
-
-
-#################################################
-#
-# use: CORSIKA_COPY_HEADERS_TO_NAMESPACE theLib theNamesapce header1.h header2.h ...
-#
-# creates a dependence of theLib on the presence of all listed header files in the
-# build-directory include/theNamespace directory
-#
-# if needed, create symbolic links from the source files to this build-directory location
-#
-# any path information from input filenames is stripped, IF path was specified it is used for the link destination,
-# if NOT the link is relative to the CMAKE_CURRENT_SOURCE_DIR
-# 
-function (CORSIKA_COPY_HEADERS_TO_NAMESPACE for_library in_namespace)
-  set (HEADERS_BUILD "")
-  foreach (HEADER ${ARGN})
-    # find eventual path, and handle it specificly
-    get_filename_component (barename ${HEADER} NAME)
-    get_filename_component (baredir ${HEADER} DIRECTORY)
-    # remove path, prepend build-directory destination
-    list (APPEND HEADERS_BUILD "${PROJECT_BINARY_DIR}/include/${in_namespace}/${barename}")
-    # define source location, use path if specified, otherwise CMAKE_CURRENT_SOURCE_DIR
-    set (FROM_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-    if (NOT "${baredir}" STREQUAL "")
-      set (FROM_DIR ${baredir})
-    endif ()
-    # define command to perform the symbolic linking
-    add_custom_command (
-      OUTPUT ${PROJECT_BINARY_DIR}/include/${in_namespace}/${barename}
-      COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/include/${in_namespace}
-      COMMAND ${CMAKE_COMMAND} -E create_symlink ${FROM_DIR}/${barename} ${PROJECT_BINARY_DIR}/include/${in_namespace}/${barename}
-      COMMENT "Generate link: ${PROJECT_BINARY_DIR}/include/${in_namespace}/${barename}"
-      )
-  endforeach (HEADER)
-  
-  # main target for this build step, depends on header files in build area
-  add_custom_target (
-    ${for_library}_BUILD
-    DEPENDS ${HEADERS_BUILD}
-    )
-  
-  # connect the _BUILD target to the main (external) target
-  add_dependencies (${for_library} ${for_library}_BUILD)
-
-endfunction (CORSIKA_COPY_HEADERS_TO_NAMESPACE)
-
-
-
-
-#################################################
-#
-# use: CORSIKA_ADD_FILES_ABSOLUTE varname
-#
-# add list of filenames with absolute paths (pointing to CMAKE_SOURCE_DIR) to ${varname} in PARAENT_SCOPE
-# 
-
-macro (CORSIKA_ADD_FILES_ABSOLUTE varname)
-  file (RELATIVE_PATH _relPath "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
-  foreach (_src ${ARGN})
-    if (_relPath)
-      list (APPEND "${varname}" "${CMAKE_SOURCE_DIR}/${_relPath}/${_src}")
-    else()
-      list (APPEND "${varname}" "${CMAKE_SOURCE_DIR}/${_src}")
-    endif()
-  endforeach()
-  if (_relPath)
-    # propagate SRCS to parent directory
-    set ("${varname}" "${${varname}}" PARENT_SCOPE)
-  endif()
-endmacro(CORSIKA_ADD_FILES_ABSOLUTE)
-
-
-
 #################################################
 #
 # central macro to register unit tests in cmake
@@ -143,6 +57,7 @@ function (CORSIKA_ADD_TEST)
   endif ()
 
   add_executable (${name} ${sources})
+  target_link_libraries (${name} CORSIKA8 Catch2)
   target_compile_options (${name} PRIVATE -g) # do not skip asserts
   target_include_directories (${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
   file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/test_outputs/)
@@ -157,7 +72,7 @@ endfunction (CORSIKA_ADD_TEST)
 
 #################################################
 #
-# central macro to register an exmaple in cmake
+# central macro to register an examples in cmake
 #
 # Examples can be globally executed by 'make run_examples'
 #
@@ -165,56 +80,37 @@ endfunction (CORSIKA_ADD_TEST)
 # Pass the name of the test.cc file as the first
 # argument, without the ".cc" extention.
 #
-# Example: CORSIKA_ADD_EXAMPLE (testSomething)
+# Example: CORSIKA_REGISTER_EXAMPLE (doSomething)
 #
-# This generates target testSomething from file testSomething.cc.
-#
-# 2) Customize sources:
-# If 1) doesn't work, use the SOURCES keyword to explicitly
-# specify the sources.
+# The TARGET doSomething must already exists,
+#    i.e. typically via add_executable (doSomething src.cc).
 #
 # Example: CORSIKA_ADD_EXAMPLE (testSomething
-#              SOURCES source1.cc source2.cc someheader.h
 #              RUN_OPTION "extra command line options"
-#              RUN_IN_GDB)
+#              )
 #
 # In all cases, you can further customize the target with
 # target_link_libraries(testSomething ...) and so on.
 #
-function (CORSIKA_ADD_EXAMPLE)
-  cmake_parse_arguments (PARSE_ARGV 1 C8_ADD_EXAMPLE "RUN_IN_GDB" "" "SOURCES;RUN_OPTIONS")
+function (CORSIKA_REGISTER_EXAMPLE)
+  cmake_parse_arguments (PARSE_ARGV 1 C8_EXAMPLE "" "" "RUN_OPTIONS")
   set (name ${ARGV0})
 
-  if (NOT C8_ADD_EXAMPLE_SOURCES)
-    set (sources ${name}.cc)
-  else ()
-    set (sources ${C8_ADD_EXAMPLE_SOURCES})
-  endif ()
-
-  if (NOT C8_ADD_EXAMPLE_RUN_OPTIONS)
+  if (NOT C8_EXAMPLE_RUN_OPTIONS)
     set (run_options "")
   else ()
-    set (run_options ${C8_ADD_EXAMPLE_RUN_OPTIONS})
+    set (run_options ${C8_EXAMPLE_RUN_OPTIONS})
   endif ()
 
-  add_executable (${name} ${sources})
   target_compile_options (${name} PRIVATE -g) # do not skip asserts
-  target_include_directories (${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
   file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/example_outputs/)
   if (TARGET run_examples)
   else ()
     add_custom_target (run_examples)
   endif ()
   add_dependencies (run_examples ${name})
-  if (C8_ADD_EXAMPLE_RUN_IN_GDB)
-    # convert cmake list into real string:
-    string (REPLACE ";" " " run_options_str "${run_options}")
-    # run the command in gdb and study backtrace a bit
-    set (CMD gdb -q --batch -ex "run ${run_options_str}" -ex bt -ex "info locals" -ex "up" -ex "info locals" -ex "up" -ex "info locals" -ex "up" -ex "info locals" -ex quit "${CMAKE_CURRENT_BINARY_DIR}/${name}") 
-  else (C8_ADD_EXAMPLE_RUN_IN_GDB)
-    # just run the command as-is
-    set (CMD ${CMAKE_CURRENT_BINARY_DIR}/${name} ${run_options})
-  endif (C8_ADD_EXAMPLE_RUN_IN_GDB)
+  # just run the command as-is
+  set (CMD ${CMAKE_CURRENT_BINARY_DIR}/${name} ${run_options})
   add_custom_command (TARGET run_examples
     POST_BUILD
     COMMAND ${CMAKE_COMMAND} -E echo ""
@@ -223,4 +119,4 @@ function (CORSIKA_ADD_EXAMPLE)
     COMMAND ${CMD} VERBATIM
     WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/example_outputs)
   install (TARGETS ${name} DESTINATION share/examples)
-endfunction (CORSIKA_ADD_EXAMPLE)
+endfunction (CORSIKA_REGISTER_EXAMPLE)
diff --git a/cmake/FindEigen3.cmake b/cmake/FindEigen3.cmake
deleted file mode 100644
index 0b36805e75ec37ba2af7a8fe9c8036f73558a618..0000000000000000000000000000000000000000
--- a/cmake/FindEigen3.cmake
+++ /dev/null
@@ -1,107 +0,0 @@
-# - Try to find Eigen3 lib
-#
-# This module supports requiring a minimum version, e.g. you can do
-#   find_package(Eigen3 3.1.2)
-# to require version 3.1.2 or newer of Eigen3.
-#
-# Once done this will define
-#
-#  EIGEN3_FOUND - system has eigen lib with correct version
-#  EIGEN3_INCLUDE_DIR - the eigen include directory
-#  EIGEN3_VERSION - eigen version
-#
-# and the following imported target:
-#
-#  Eigen3::Eigen - The header-only Eigen library
-#
-# This module reads hints about search locations from 
-# the following environment variables:
-#
-# EIGEN3_ROOT
-# EIGEN3_ROOT_DIR
-
-# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
-# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr>
-# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
-# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
-
-if(NOT Eigen3_FIND_VERSION)
-  if(NOT Eigen3_FIND_VERSION_MAJOR)
-    set(Eigen3_FIND_VERSION_MAJOR 2)
-  endif()
-  if(NOT Eigen3_FIND_VERSION_MINOR)
-    set(Eigen3_FIND_VERSION_MINOR 91)
-  endif()
-  if(NOT Eigen3_FIND_VERSION_PATCH)
-    set(Eigen3_FIND_VERSION_PATCH 0)
-  endif()
-
-  set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
-endif()
-
-macro(_eigen3_check_version)
-  file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
-
-  string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
-  set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
-  string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
-  set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
-  string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
-  set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
-
-  set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
-  if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
-    set(EIGEN3_VERSION_OK FALSE)
-  else()
-    set(EIGEN3_VERSION_OK TRUE)
-  endif()
-
-  if(NOT EIGEN3_VERSION_OK)
-
-    message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
-                   "but at least version ${Eigen3_FIND_VERSION} is required")
-  endif()
-endmacro()
-
-if (EIGEN3_INCLUDE_DIR)
-
-  # in cache already
-  _eigen3_check_version()
-  set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
-  set(Eigen3_FOUND ${EIGEN3_VERSION_OK})
-
-else ()
-  
-  # search first if an Eigen3Config.cmake is available in the system,
-  # if successful this would set EIGEN3_INCLUDE_DIR and the rest of
-  # the script will work as usual
-  find_package(Eigen3 ${Eigen3_FIND_VERSION} NO_MODULE QUIET)
-
-  if(NOT EIGEN3_INCLUDE_DIR)
-    find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
-        HINTS
-        ENV EIGEN3_ROOT 
-        ENV EIGEN3_ROOT_DIR
-        PATHS
-        ${CMAKE_INSTALL_PREFIX}/include
-        ${KDE4_INCLUDE_DIR}
-        PATH_SUFFIXES eigen3 eigen
-      )
-  endif()
-
-  if(EIGEN3_INCLUDE_DIR)
-    _eigen3_check_version()
-  endif()
-
-  include(FindPackageHandleStandardArgs)
-  find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
-
-  mark_as_advanced(EIGEN3_INCLUDE_DIR)
-
-endif()
-
-if(EIGEN3_FOUND AND NOT TARGET Eigen3::Eigen)
-  add_library(Eigen3::Eigen INTERFACE IMPORTED)
-  set_target_properties(Eigen3::Eigen PROPERTIES
-    INTERFACE_INCLUDE_DIRECTORIES "${EIGEN3_INCLUDE_DIR}")
-endif()
diff --git a/corsika/corsika.hpp b/corsika/corsika.hpp
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..137cccc6b44152af8fad6d3f479ecba41e72aed3 100644
--- a/corsika/corsika.hpp
+++ b/corsika/corsika.hpp
@@ -0,0 +1,33 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+//  Usage:
+//  to get the version X.YY.Z,
+//  set CORSIKA_VERSION X0YY0Z
+//
+#define CORSIKA_VERSION 800000
+
+/*! \def CORSIKA_MAJOR_VERSION
+ *  \brief The preprocessor macro \p CORSIKA_MAJOR_VERSION encodes the
+ *         major version number of CORSIKA.
+ */
+#define CORSIKA_MAJOR_VERSION (CORSIKA_VERSION / 100000)
+
+/*! \def CORSIKA_MINOR_VERSION
+ *  \brief The preprocessor macro \p CORSIKA_MINOR_VERSION encodes the
+ *         minor version number of CORSIKA.
+ */
+#define CORSIKA_MINOR_VERSION (CORSIKA_VERSION / 100 % 1000)
+
+/*! \def CORSIKA_PATCH_NUMBER
+ *  \brief The preprocessor macro \p CORSIKA_PATCH_NUMBER encodes the
+ *         patch number of the CORSIKA library.
+ */
+#define CORSIKA_PATCH_NUMBER 0
\ No newline at end of file
diff --git a/corsika/detail/framework/core/Cascade.inl b/corsika/detail/framework/core/Cascade.inl
index 7dba8399ec77bc72bf4bad4b80bd27770500b9d1..8024b83ddab77dbc85904f11ae6a9fc033d77a67 100644
--- a/corsika/detail/framework/core/Cascade.inl
+++ b/corsika/detail/framework/core/Cascade.inl
@@ -10,253 +10,245 @@
 
 #pragma once
 
+#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
 #include <corsika/framework/random/ExponentialDistribution.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
 #include <corsika/framework/random/UniformRealDistribution.hpp>
 #include <corsika/framework/stack/SecondaryView.hpp>
+#include <corsika/media/Environment.hpp>
+
+#include <corsika/setup/SetupStack.hpp>
+#include <corsika/setup/SetupTrajectory.hpp>
+
 #include <cassert>
 #include <cmath>
 #include <iostream>
 #include <limits>
 #include <type_traits>
 
-#include <boost/type_index.hpp>
-
-#include <corsika/media/Environment.hpp>
-#include <corsika/setup/SetupStack.hpp>
-#include <corsika/setup/SetupTrajectory.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp>
-#include <corsika/framework/core/PhysicalUnits.hpp>
-
-using boost::typeindex::type_id_with_cvr;
-
 /**
  * The cascade namespace assembles all objects needed to simulate full particles cascades.
  */
 
 namespace corsika {
 
-
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    void Cascade<TTracking, TProcessList, TStack, TStackView >::Init()
-    {
-      fProcessSequence.Init();
-      fStack.Init();
-    }
-
-
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    void Cascade<TTracking, TProcessList, TStack, TStackView >::SetNodes() {
-      std::for_each(fStack.begin(), fStack.end(), [&](auto& p) {
-        auto const* numericalNode =
-            fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition());
-        p.SetNode(numericalNode);
-      });
-    }
-
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    void Cascade<TTracking, TProcessList, TStack, TStackView >::Run()
-    {
-      SetNodes();
-
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  void Cascade<TTracking, TProcessList, TStack, TStackView>::Init() {
+    fProcessSequence.Init();
+    fStack.Init();
+  }
+
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  void Cascade<TTracking, TProcessList, TStack, TStackView>::SetNodes() {
+    std::for_each(fStack.begin(), fStack.end(), [&](auto& p) {
+      auto const* numericalNode =
+          fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition());
+      p.SetNode(numericalNode);
+    });
+  }
+
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  void Cascade<TTracking, TProcessList, TStack, TStackView>::Run() {
+    SetNodes();
+
+    while (!fStack.IsEmpty()) {
       while (!fStack.IsEmpty()) {
-        while (!fStack.IsEmpty()) {
-          auto pNext = fStack.GetNextParticle();
-          std::cout << "========= next: " << pNext.GetPID() << std::endl;
-          Step(pNext);
-          std::cout << "========= stack ============" << std::endl;
-          fProcessSequence.DoStack(fStack);
-        }
-        // do cascade equations, which can put new particles on Stack,
-        // thus, the double loop
-        // DoCascadeEquations();
+        auto pNext = fStack.GetNextParticle();
+        std::cout << "========= next: " << pNext.GetPID() << std::endl;
+        Step(pNext);
+        std::cout << "========= stack ============" << std::endl;
+        fProcessSequence.DoStack(fStack);
       }
+      // do cascade equations, which can put new particles on Stack,
+      // thus, the double loop
+      // DoCascadeEquations();
     }
-
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    void Cascade<TTracking, TProcessList, TStack, TStackView >::forceInteraction()
-    {
-      std::cout << "forced interaction!" << std::endl;
-      auto vParticle = fStack.GetNextParticle();
-      TStackView secondaries(vParticle);
-      auto projectile = secondaries.GetProjectile();
-      interaction(vParticle, projectile);
-      fProcessSequence.DoSecondaries(secondaries);
-      vParticle.Delete(); // todo: this should be reviewed, see below
+  }
+
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  void Cascade<TTracking, TProcessList, TStack, TStackView>::forceInteraction() {
+    std::cout << "forced interaction!" << std::endl;
+    auto vParticle = fStack.GetNextParticle();
+    TStackView secondaries(vParticle);
+    auto projectile = secondaries.GetProjectile();
+    interaction(vParticle, projectile);
+    fProcessSequence.DoSecondaries(secondaries);
+    vParticle.Delete(); // todo: this should be reviewed, see below
+  }
+
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  void Cascade<TTracking, TProcessList, TStack, TStackView>::Step(Particle& vParticle) {
+
+    // determine geometric tracking
+    auto [step, geomMaxLength, nextVol] = fTracking.GetTrack(vParticle);
+    [[maybe_unused]] auto const& dummy_nextVol = nextVol;
+
+    // determine combined total interaction length (inverse)
+    InverseGrammageType const total_inv_lambda =
+        fProcessSequence.GetTotalInverseInteractionLength(vParticle);
+
+    // sample random exponential step length in grammage
+    corsika::ExponentialDistribution expDist(1 / total_inv_lambda);
+    GrammageType const next_interact = expDist(fRNG);
+
+    std::cout << "total_inv_lambda=" << total_inv_lambda
+              << ", next_interact=" << next_interact << std::endl;
+
+    auto const* currentLogicalNode = vParticle.GetNode();
+
+    // assert that particle stays outside void Universe if it has no
+    // model properties set
+    assert(currentLogicalNode != &*fEnvironment.GetUniverse() ||
+           fEnvironment.GetUniverse()->HasModelProperties());
+
+    // convert next_step from grammage to length
+    LengthType const distance_interact =
+        currentLogicalNode->GetModelProperties().ArclengthFromGrammage(step,
+                                                                       next_interact);
+
+    // determine the maximum geometric step length
+    LengthType const distance_max = fProcessSequence.MaxStepLength(vParticle, step);
+    std::cout << "distance_max=" << distance_max << std::endl;
+
+    // determine combined total inverse decay time
+    InverseTimeType const total_inv_lifetime =
+        fProcessSequence.GetTotalInverseLifetime(vParticle);
+
+    // sample random exponential decay time
+    corsika::ExponentialDistribution expDistDecay(1 / total_inv_lifetime);
+    TimeType const next_decay = expDistDecay(fRNG);
+    std::cout << "total_inv_lifetime=" << total_inv_lifetime
+              << ", next_decay=" << next_decay << std::endl;
+
+    // convert next_decay from time to length [m]
+    LengthType const distance_decay = next_decay * vParticle.GetMomentum().norm() /
+                                      vParticle.GetEnergy() * constants::c;
+
+    // take minimum of geometry, interaction, decay for next step
+    auto const min_distance =
+        std::min({distance_interact, distance_decay, distance_max, geomMaxLength});
+
+    std::cout << " move particle by : " << min_distance << std::endl;
+
+    // here the particle is actually moved along the trajectory to new position:
+    // std::visit(setup::ParticleUpdate<particle_type>{vParticle}, step);
+    vParticle.SetPosition(step.PositionFromArclength(min_distance));
+    // .... also update time, momentum, direction, ...
+    vParticle.SetTime(vParticle.GetTime() + min_distance / constants::c);
+
+    step.LimitEndTo(min_distance);
+
+    // apply all continuous processes on particle + track
+    corsika::EProcessReturn status = fProcessSequence.DoContinuous(vParticle, step);
+
+    if (status == corsika::EProcessReturn::eParticleAbsorbed) {
+      std::cout << "Cascade: delete absorbed particle " << vParticle.GetPID() << " "
+                << vParticle.GetEnergy() / 1_GeV << "GeV" << std::endl;
+      vParticle.Delete();
+      return;
     }
 
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    void Cascade<TTracking, TProcessList, TStack, TStackView >::Step(Particle& vParticle)
-    {
-      using namespace corsika;
-      using namespace corsika::units::si;
-
-      // determine geometric tracking
-      auto [step, geomMaxLength, nextVol] = fTracking.GetTrack(vParticle);
-      [[maybe_unused]] auto const& dummy_nextVol = nextVol;
-
-      // determine combined total interaction length (inverse)
-      InverseGrammageType const total_inv_lambda =
-          fProcessSequence.GetTotalInverseInteractionLength(vParticle);
-
-      // sample random exponential step length in grammage
-      corsika::ExponentialDistribution expDist(1 / total_inv_lambda);
-      GrammageType const next_interact = expDist(fRNG);
-
-      std::cout << "total_inv_lambda=" << total_inv_lambda
-                << ", next_interact=" << next_interact << std::endl;
-
-      auto const* currentLogicalNode = vParticle.GetNode();
-
-      // assert that particle stays outside void Universe if it has no
-      // model properties set
-      assert(currentLogicalNode != &*fEnvironment.GetUniverse() ||
-             fEnvironment.GetUniverse()->HasModelProperties());
-
-      // convert next_step from grammage to length
-      LengthType const distance_interact =
-          currentLogicalNode->GetModelProperties().ArclengthFromGrammage(step,
-                                                                         next_interact);
-
-      // determine the maximum geometric step length
-      LengthType const distance_max = fProcessSequence.MaxStepLength(vParticle, step);
-      std::cout << "distance_max=" << distance_max << std::endl;
-
-      // determine combined total inverse decay time
-      InverseTimeType const total_inv_lifetime =
-          fProcessSequence.GetTotalInverseLifetime(vParticle);
-
-      // sample random exponential decay time
-      corsika::ExponentialDistribution expDistDecay(1 / total_inv_lifetime);
-      TimeType const next_decay = expDistDecay(fRNG);
-      std::cout << "total_inv_lifetime=" << total_inv_lifetime
-                << ", next_decay=" << next_decay << std::endl;
+    std::cout << "sth. happening before geometric limit ? "
+              << ((min_distance < geomMaxLength) ? "yes" : "no") << std::endl;
 
-      // convert next_decay from time to length [m]
-      LengthType const distance_decay = next_decay * vParticle.GetMomentum().norm() /
-                                        vParticle.GetEnergy() * units::constants::c;
+    if (min_distance < geomMaxLength) { // interaction to happen within geometric limit
 
-      // take minimum of geometry, interaction, decay for next step
-      auto const min_distance =
-          std::min({distance_interact, distance_decay, distance_max, geomMaxLength});
+      // check whether decay or interaction limits this step the
+      // outcome of decay or interaction MAY be a) new particles in
+      // secondaries, b) the projectile particle deleted (or
+      // changed)
 
-      std::cout << " move particle by : " << min_distance << std::endl;
+      TStackView secondaries(vParticle);
 
-      // here the particle is actually moved along the trajectory to new position:
-      // std::visit(setup::ParticleUpdate<particle_type>{vParticle}, step);
-      vParticle.SetPosition(step.PositionFromArclength(min_distance));
-      // .... also update time, momentum, direction, ...
-      vParticle.SetTime(vParticle.GetTime() + min_distance / units::constants::c);
+      if (min_distance != distance_max) {
+        /*
+          Create SecondaryView object on Stack. The data container
+          remains untouched and identical, and 'projectil' is identical
+          to 'vParticle' above this line. However,
+          projectil.AddSecondaries populate the SecondaryView, which can
+          then be used afterwards for further processing. Thus: it is
+          important to use projectle (and not vParticle) for Interaction,
+          and Decay!
+        */
+
+        [[maybe_unused]] auto projectile = secondaries.GetProjectile();
+
+        if (min_distance == distance_interact) {
+          interaction(vParticle, projectile);
+        } else {
+          assert(min_distance == distance_decay);
+          decay(vParticle, projectile);
+          // make sure particle actually did decay if it should have done so
+          if (secondaries.GetSize() == 1 &&
+              projectile.GetPID() == secondaries.GetNextParticle().GetPID())
+            throw std::runtime_error("Cascade::Step: particle_type decays into itself!");
+        }
 
-      step.LimitEndTo(min_distance);
+        fProcessSequence.DoSecondaries(secondaries);
+        vParticle.Delete(); // todo: this should be reviewed. Where
+                            // exactly are particles best deleted, and
+                            // where they should NOT be
+                            // deleted... maybe Delete function should
+                            // be "protected" and not accessible to physics
 
-      // apply all continuous processes on particle + track
-      corsika::EProcessReturn status = fProcessSequence.DoContinuous(vParticle, step);
+      } else { // step-length limitation within volume
 
-      if (status == corsika::EProcessReturn::eParticleAbsorbed) {
-        std::cout << "Cascade: delete absorbed particle " << vParticle.GetPID() << " "
-                  << vParticle.GetEnergy() / 1_GeV << "GeV" << std::endl;
-        vParticle.Delete();
-        return;
+        std::cout << "step-length limitation" << std::endl;
+        fProcessSequence.DoSecondaries(secondaries);
       }
 
-      std::cout << "sth. happening before geometric limit ? "
-                << ((min_distance < geomMaxLength) ? "yes" : "no") << std::endl;
-
-      if (min_distance < geomMaxLength) { // interaction to happen within geometric limit
-
-        // check whether decay or interaction limits this step the
-        // outcome of decay or interaction MAY be a) new particles in
-        // secondaries, b) the projectile particle deleted (or
-        // changed)
-
-        TStackView secondaries(vParticle);
-
-        if (min_distance != distance_max) {
-          /*
-            Create SecondaryView object on Stack. The data container
-            remains untouched and identical, and 'projectil' is identical
-            to 'vParticle' above this line. However,
-            projectil.AddSecondaries populate the SecondaryView, which can
-            then be used afterwards for further processing. Thus: it is
-            important to use projectle (and not vParticle) for Interaction,
-            and Decay!
-          */
-
-          [[maybe_unused]] auto projectile = secondaries.GetProjectile();
-
-          if (min_distance == distance_interact) {
-            interaction(vParticle, projectile);
-          } else {
-            assert(min_distance == distance_decay);
-            decay(vParticle, projectile);
-            // make sure particle actually did decay if it should have done so
-            if (secondaries.GetSize() == 1 &&
-                projectile.GetPID() == secondaries.GetNextParticle().GetPID())
-              throw std::runtime_error("Cascade::Step: particle_type decays into itself!");
-          }
-
-          fProcessSequence.DoSecondaries(secondaries);
-          vParticle.Delete(); // todo: this should be reviewed. Where
-                              // exactly are particles best deleted, and
-                              // where they should NOT be
-                              // deleted... maybe Delete function should
-                              // be "protected" and not accessible to physics
-
-        } else { // step-length limitation within volume
-
-          std::cout << "step-length limitation" << std::endl;
-          fProcessSequence.DoSecondaries(secondaries);
-        }
-
-        [[maybe_unused]] auto const assertion = [&] {
-          auto const* numericalNodeAfterStep =
-              fEnvironment.GetUniverse()->GetContainingNode(vParticle.GetPosition());
-          return numericalNodeAfterStep == currentLogicalNode;
-        };
-
-        assert(assertion()); // numerical and logical nodes don't match
-      } else {               // boundary crossing, step is limited by volume boundary
-        std::cout << "boundary crossing! next node = " << nextVol << std::endl;
-        vParticle.SetNode(nextVol);
-        // DoBoundary may delete the particle (or not)
-        fProcessSequence.DoBoundaryCrossing(vParticle, *currentLogicalNode, *nextVol);
-      }
+      [[maybe_unused]] auto const assertion = [&] {
+        auto const* numericalNodeAfterStep =
+            fEnvironment.GetUniverse()->GetContainingNode(vParticle.GetPosition());
+        return numericalNodeAfterStep == currentLogicalNode;
+      };
+
+      assert(assertion()); // numerical and logical nodes don't match
+    } else {               // boundary crossing, step is limited by volume boundary
+      std::cout << "boundary crossing! next node = " << nextVol << std::endl;
+      vParticle.SetNode(nextVol);
+      // DoBoundary may delete the particle (or not)
+      fProcessSequence.DoBoundaryCrossing(vParticle, *currentLogicalNode, *nextVol);
     }
-
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    auto Cascade<TTracking, TProcessList, TStack, TStackView >::decay(Particle& particle,
-               decltype(std::declval<TStackView>().GetProjectile()) projectile)
-    {
-      std::cout << "decay" << std::endl;
-      units::si::InverseTimeType const actual_decay_time =
-          fProcessSequence.GetTotalInverseLifetime(particle);
-
-      corsika::UniformRealDistribution<units::si::InverseTimeType> uniDist(
-          actual_decay_time);
-      const auto sample_process = uniDist(fRNG);
-      units::si::InverseTimeType inv_decay_count = units::si::InverseTimeType::zero();
-      return fProcessSequence.SelectDecay(particle, projectile, sample_process,
-                                          inv_decay_count);
-    }
-
-    template <typename TTracking, typename TProcessList, typename TStack, typename TStackView>
-    auto Cascade<TTracking, TProcessList, TStack, TStackView >::interaction(Particle& particle,
-                     decltype(std::declval<TStackView>().GetProjectile()) projectile)
-    {
-      std::cout << "collide" << std::endl;
-
-      units::si::InverseGrammageType const current_inv_length =
-          fProcessSequence.GetTotalInverseInteractionLength(particle);
-
-      corsika::UniformRealDistribution<units::si::InverseGrammageType> uniDist(
-          current_inv_length);
-      const auto sample_process = uniDist(fRNG);
-      auto inv_lambda_count = units::si::InverseGrammageType::zero();
-      return fProcessSequence.SelectInteraction(particle, projectile, sample_process,
-                                                inv_lambda_count);
-    }
-
+  }
+
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  auto Cascade<TTracking, TProcessList, TStack, TStackView>::decay(
+      Particle& particle,
+      decltype(std::declval<TStackView>().GetProjectile()) projectile) {
+    std::cout << "decay" << std::endl;
+    InverseTimeType const actual_decay_time =
+        fProcessSequence.GetTotalInverseLifetime(particle);
+
+    corsika::UniformRealDistribution<InverseTimeType> uniDist(actual_decay_time);
+    const auto sample_process = uniDist(fRNG);
+    InverseTimeType inv_decay_count = InverseTimeType::zero();
+    return fProcessSequence.SelectDecay(particle, projectile, sample_process,
+                                        inv_decay_count);
+  }
+
+  template <typename TTracking, typename TProcessList, typename TStack,
+            typename TStackView>
+  auto Cascade<TTracking, TProcessList, TStack, TStackView>::interaction(
+      Particle& particle,
+      decltype(std::declval<TStackView>().GetProjectile()) projectile) {
+    std::cout << "collide" << std::endl;
+
+    InverseGrammageType const current_inv_length =
+        fProcessSequence.GetTotalInverseInteractionLength(particle);
+
+    corsika::UniformRealDistribution<InverseGrammageType> uniDist(current_inv_length);
+    const auto sample_process = uniDist(fRNG);
+    auto inv_lambda_count = InverseGrammageType::zero();
+    return fProcessSequence.SelectInteraction(particle, projectile, sample_process,
+                                              inv_lambda_count);
+  }
 
 } // namespace corsika
-
diff --git a/corsika/detail/framework/geometry/CoordinateSystem.inl b/corsika/detail/framework/geometry/CoordinateSystem.inl
index 732f44e0955c8613c42dd793dbd4b0f6db04bca3..608c33da816c61b42b0a3eb6ecfb41dfa7b6c336 100644
--- a/corsika/detail/framework/geometry/CoordinateSystem.inl
+++ b/corsika/detail/framework/geometry/CoordinateSystem.inl
@@ -78,7 +78,7 @@ namespace corsika {
     }
 
     template <typename TDim>
-    auto CoordinateSystem::translateAndRotate(QuantityVector<phys::units::length_d> translation, QuantityVector<TDim> axis, double angle)
+    auto CoordinateSystem::translateAndRotate(QuantityVector<length_d> translation, QuantityVector<TDim> axis, double angle)
     {
       if (axis.eVector.isZero()) {
         throw std::runtime_error("null-vector given as axis parameter");
diff --git a/corsika/detail/framework/geometry/FourVector.inl b/corsika/detail/framework/geometry/FourVector.inl
index 4d629b65964cf5dc398f586fa8439b2c88a2296d..05fee3c86d1767363af3c72ba1ff26ed431f6ee4 100644
--- a/corsika/detail/framework/geometry/FourVector.inl
+++ b/corsika/detail/framework/geometry/FourVector.inl
@@ -15,137 +15,117 @@
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Vector.hpp>
 
+namespace corsika {
 
+  template <typename TimeType, typename SpaceVecType>
+  TimeType FourVector<TimeType, SpaceVecType>::GetTimeLikeComponent() const {
+    return fTimeLike;
+  }
 
-namespace corsika {
+  template <typename TimeType, typename SpaceVecType>
+  SpaceVecType& FourVector<TimeType, SpaceVecType>::GetSpaceLikeComponents() {
+    return fSpaceLike;
+  }
 
+  template <typename TimeType, typename SpaceVecType>
+  const SpaceVecType& FourVector<TimeType, SpaceVecType>::GetSpaceLikeComponents() const {
+    return fSpaceLike;
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  auto FourVector<TimeType, SpaceVecType>::GetNormSqr() const {
+    return GetTimeSquared() - fSpaceLike.squaredNorm();
+  }
 
-	template <typename TimeType, typename SpaceVecType>
-    TimeType FourVector<TimeType, SpaceVecType>::GetTimeLikeComponent() const
-    {
-    	return fTimeLike;
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    SpaceVecType& FourVector<TimeType, SpaceVecType>::GetSpaceLikeComponents()
-	{
-		return fSpaceLike;
-	}
-
-
-	template <typename TimeType, typename SpaceVecType>
-    const SpaceVecType& FourVector<TimeType, SpaceVecType>::GetSpaceLikeComponents() const
-	{
-		return fSpaceLike;
-	}
-
-	template <typename TimeType, typename SpaceVecType>
-    auto FourVector<TimeType, SpaceVecType>::GetNormSqr() const
-	{
-		return GetTimeSquared() - fSpaceLike.squaredNorm();
-	}
-
-	template <typename TimeType, typename SpaceVecType>
-	typename FourVector<TimeType, SpaceVecType>::SpaceType
-	FourVector<TimeType, SpaceVecType>::GetNorm() const
-	{
-
-		return sqrt(abs(GetNormSqr()));
-	}
-
-	template <typename TimeType, typename SpaceVecType>
-    bool FourVector<TimeType, SpaceVecType>::IsTimelike() const
-	{
-      return GetTimeSquared() < fSpaceLike.squaredNorm();
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    bool FourVector<TimeType, SpaceVecType>::IsSpacelike() const {
-      return GetTimeSquared() > fSpaceLike.squaredNorm();
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    FourVector<TimeType, SpaceVecType>&
-	FourVector<TimeType, SpaceVecType>::operator+=(const FourVector& b)
-	{
-      fTimeLike += b.fTimeLike;
-      fSpaceLike += b.fSpaceLike;
-
-      return *this;
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    FourVector<TimeType, SpaceVecType>&
-	FourVector<TimeType, SpaceVecType>::operator-=(const FourVector& b)
-	{
-      fTimeLike -= b.fTimeLike;
-      fSpaceLike -= b.fSpaceLike;
-      return *this;
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    FourVector<TimeType, SpaceVecType>&
-	FourVector<TimeType, SpaceVecType>::operator*=(const double b)
-	{
-      fTimeLike *= b;
-      fSpaceLike *= b;
-      return *this;
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    FourVector<TimeType, SpaceVecType>&
-	FourVector<TimeType, SpaceVecType>::operator/=(const double b)
-	{
-      fTimeLike /= b;
-      fSpaceLike.GetComponents() /= b; // TODO: WHY IS THIS??????
-      return *this;
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    FourVector<TimeType, SpaceVecType>&
-	FourVector<TimeType, SpaceVecType>::operator/(const double b)
-	{
-      *this /= b;
-      return *this;
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-	typename FourVector<TimeType, SpaceVecType>::SpaceType
-	FourVector<TimeType, SpaceVecType>::operator*(const FourVector& b)
-	{
-      if constexpr (std::is_same<typename std::decay<TimeType>::type,
-                                 decltype(std::declval<SpaceType>() /
-                                          corsika::units::si::meter *
-                                          corsika::units::si::second)>::value)
-        return fTimeLike * b.fTimeLike *
-                   (corsika::units::constants::c * corsika::units::constants::c) -
-               fSpaceLike.norm();
-      else
-        return fTimeLike * fTimeLike - fSpaceLike.norm();
-    }
-
-	template <typename TimeType, typename SpaceVecType>
-    auto FourVector<TimeType, SpaceVecType>::GetTimeSquared() const
-	{
-      if constexpr (std::is_same<typename std::decay<TimeType>::type,
-                                 decltype(std::declval<SpaceType>() /
-                                          corsika::units::si::meter *
-                                          corsika::units::si::second)>::value)
-        return fTimeLike * fTimeLike *
-               (corsika::units::constants::c * corsika::units::constants::c);
-      else
-        return fTimeLike * fTimeLike;
-    }
+  template <typename TimeType, typename SpaceVecType>
+  typename FourVector<TimeType, SpaceVecType>::SpaceType
+  FourVector<TimeType, SpaceVecType>::GetNorm() const {
+
+    return sqrt(abs(GetNormSqr()));
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  bool FourVector<TimeType, SpaceVecType>::IsTimelike() const {
+    return GetTimeSquared() < fSpaceLike.squaredNorm();
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  bool FourVector<TimeType, SpaceVecType>::IsSpacelike() const {
+    return GetTimeSquared() > fSpaceLike.squaredNorm();
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  FourVector<TimeType, SpaceVecType>& FourVector<TimeType, SpaceVecType>::operator+=(
+      const FourVector& b) {
+    fTimeLike += b.fTimeLike;
+    fSpaceLike += b.fSpaceLike;
+
+    return *this;
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  FourVector<TimeType, SpaceVecType>& FourVector<TimeType, SpaceVecType>::operator-=(
+      const FourVector& b) {
+    fTimeLike -= b.fTimeLike;
+    fSpaceLike -= b.fSpaceLike;
+    return *this;
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  FourVector<TimeType, SpaceVecType>& FourVector<TimeType, SpaceVecType>::operator*=(
+      const double b) {
+    fTimeLike *= b;
+    fSpaceLike *= b;
+    return *this;
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  FourVector<TimeType, SpaceVecType>& FourVector<TimeType, SpaceVecType>::operator/=(
+      const double b) {
+    fTimeLike /= b;
+    fSpaceLike.GetComponents() /= b; // TODO: WHY IS THIS??????
+    return *this;
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  FourVector<TimeType, SpaceVecType>& FourVector<TimeType, SpaceVecType>::operator/(
+      const double b) {
+    *this /= b;
+    return *this;
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  typename FourVector<TimeType, SpaceVecType>::SpaceType
+      FourVector<TimeType, SpaceVecType>::operator*(const FourVector& b) {
+    if constexpr (std::is_same<typename std::decay<TimeType>::type,
+                               decltype(std::declval<SpaceType>() / meter *
+                                        second)>::value)
+      return fTimeLike * b.fTimeLike * (constants::c * constants::c) - fSpaceLike.norm();
+    else
+      return fTimeLike * fTimeLike - fSpaceLike.norm();
+  }
+
+  template <typename TimeType, typename SpaceVecType>
+  auto FourVector<TimeType, SpaceVecType>::GetTimeSquared() const {
+    if constexpr (std::is_same<typename std::decay<TimeType>::type,
+                               decltype(std::declval<SpaceType>() / meter *
+                                        second)>::value)
+      return fTimeLike * fTimeLike * constants::cSquared;
+    else
+      return fTimeLike * fTimeLike;
+  }
 
   /**
       The math operator+
    */
   template <typename TimeType, typename SpaceVecType>
-  inline FourVector<typename std::decay<TimeType>::type, typename std::decay<SpaceVecType>::type>
-  operator+(const FourVector<TimeType, SpaceVecType>& a, const FourVector<TimeType, SpaceVecType>& b)
-  {
+  inline FourVector<typename std::decay<TimeType>::type,
+                    typename std::decay<SpaceVecType>::type>
+  operator+(const FourVector<TimeType, SpaceVecType>& a,
+            const FourVector<TimeType, SpaceVecType>& b) {
     return FourVector<typename std::decay<TimeType>::type,
-    		          typename std::decay<SpaceVecType>::type>(a.fTimeLike + b.fTimeLike, a.fSpaceLike + b.fSpaceLike);
+                      typename std::decay<SpaceVecType>::type>(
+        a.fTimeLike + b.fTimeLike, a.fSpaceLike + b.fSpaceLike);
   }
 
   /**
@@ -154,8 +134,8 @@ namespace corsika {
   template <typename TimeType, typename SpaceVecType>
   inline FourVector<typename std::decay<TimeType>::type,
                     typename std::decay<SpaceVecType>::type>
-  operator-(const FourVector<TimeType, SpaceVecType>& a, const FourVector<TimeType, SpaceVecType>& b)
-  {
+  operator-(const FourVector<TimeType, SpaceVecType>& a,
+            const FourVector<TimeType, SpaceVecType>& b) {
     return FourVector<typename std::decay<TimeType>::type,
                       typename std::decay<SpaceVecType>::type>(
         a.fTimeLike - b.fTimeLike, a.fSpaceLike - b.fSpaceLike);
@@ -167,8 +147,7 @@ namespace corsika {
   template <typename TimeType, typename SpaceVecType>
   inline FourVector<typename std::decay<TimeType>::type,
                     typename std::decay<SpaceVecType>::type>
-  operator*(const FourVector<TimeType, SpaceVecType>& a, const double b)
-  {
+  operator*(const FourVector<TimeType, SpaceVecType>& a, const double b) {
     return FourVector<typename std::decay<TimeType>::type,
                       typename std::decay<SpaceVecType>::type>(a.fTimeLike * b,
                                                                a.fSpaceLike * b);
diff --git a/corsika/detail/framework/geometry/Helix.inl b/corsika/detail/framework/geometry/Helix.inl
index 103aac9826c6e314e3b7b5e42ba0cf8e0f34152e..f023dec0b31713d91437aeffbbed0ce2e433e2a2 100644
--- a/corsika/detail/framework/geometry/Helix.inl
+++ b/corsika/detail/framework/geometry/Helix.inl
@@ -17,35 +17,23 @@
 
 namespace corsika {
 
+  Point Helix::GetPosition(TimeType t) const {
+    return r0 + vPar * t +
+           (vPerp * (cos(omegaC * t) - 1) + uPerp * sin(omegaC * t)) / omegaC;
+  }
 
-    Point Helix::GetPosition(corsika::units::si::TimeType t) const
-    {
-      return r0 + vPar * t +
-             (vPerp * (cos(omegaC * t) - 1) + uPerp * sin(omegaC * t)) / omegaC;
-    }
+  Point Helix::PositionFromArclength(LengthType l) const {
+    return GetPosition(TimeFromArclength(l));
+  }
 
-    Point Helix::PositionFromArclength(corsika::units::si::LengthType l) const
-    {
-      return GetPosition(TimeFromArclength(l));
-    }
+  LengthType Helix::GetRadius() const { return radius; }
 
-    units::si::LengthType Helix::GetRadius() const
-    {
-    	return radius;
-    }
-
-    corsika::units::si::LengthType
-    Helix::ArcLength(corsika::units::si::TimeType t1, corsika::units::si::TimeType t2) const
-    {
-      return (vPar + vPerp).norm() * (t2 - t1);
-    }
-
-    corsika::units::si::TimeType
-	Helix::TimeFromArclength(corsika::units::si::LengthType l) const
-    {
-      return l / (vPar + vPerp).norm();
-    }
+  LengthType Helix::ArcLength(TimeType t1, TimeType t2) const {
+    return (vPar + vPerp).norm() * (t2 - t1);
+  }
 
+  TimeType Helix::TimeFromArclength(LengthType l) const {
+    return l / (vPar + vPerp).norm();
+  }
 
 } // namespace corsika
-
diff --git a/corsika/detail/framework/geometry/Line.inl b/corsika/detail/framework/geometry/Line.inl
index 5446bad4e52e002754d734cee62fac6a44548b95..60e78b622a43c37cf69a75c5b1841029cd472d9b 100644
--- a/corsika/detail/framework/geometry/Line.inl
+++ b/corsika/detail/framework/geometry/Line.inl
@@ -16,39 +16,20 @@
 
 namespace corsika {
 
+  Point Line::GetPosition(TimeType t) const { return r0 + v0 * t; }
 
-    Point Line::GetPosition(units::si::TimeType t) const
-    {
-    	return r0 + v0 * t;
-    }
+  Point Line::PositionFromArclength(LengthType l) const {
+    return r0 + v0.normalized() * l;
+  }
 
-    Point Line::PositionFromArclength(units::si::LengthType l) const
-    {
-      return r0 + v0.normalized() * l;
-    }
+  LengthType Line::ArcLength(TimeType t1, TimeType t2) const {
+    return v0.norm() * (t2 - t1);
+  }
 
-    units::si::LengthType
-	Line::ArcLength(units::si::TimeType t1, units::si::TimeType t2) const
-    {
-      return v0.norm() * (t2 - t1);
-    }
+  TimeType Line::TimeFromArclength(LengthType t) const { return t / v0.norm(); }
 
-    units::si::TimeType
-	Line::TimeFromArclength( units::si::LengthType t) const
-    {
-      return t / v0.norm();
-    }
-
-    const Point& Line::GetR0() const
-    {
-    	return r0;
-    }
-
-    const Line::VelocityVec& Line::GetV0() const
-    {
-    	return v0;
-    }
+  const Point& Line::GetR0() const { return r0; }
 
+  const Line::VelocityVec& Line::GetV0() const { return v0; }
 
 } // namespace corsika
-
diff --git a/corsika/detail/framework/geometry/Plane.inl b/corsika/detail/framework/geometry/Plane.inl
index c63749215efbd087b2ec70670fd95676714209c0..470a598114ba21d888fe83762c22c1bb7555b20a 100644
--- a/corsika/detail/framework/geometry/Plane.inl
+++ b/corsika/detail/framework/geometry/Plane.inl
@@ -16,27 +16,16 @@
 
 namespace corsika {
 
+  inline bool Plane::IsAbove(Point const& vP) const {
+    return fNormal.dot(vP - fCenter) > LengthType::zero();
+  }
 
-    inline bool Plane::IsAbove(Point const& vP) const
-    {
-      return fNormal.dot(vP - fCenter) > corsika::units::si::LengthType::zero();
-    }
+  inline LengthType Plane::DistanceTo(corsika::Point const& vP) const {
+    return (fNormal * (vP - fCenter).dot(fNormal)).norm();
+  }
 
-    inline units::si::LengthType Plane::DistanceTo(corsika::Point const& vP) const
-    {
-      return (fNormal * (vP - fCenter).dot(fNormal)).norm();
-    }
-
-    inline Point const& Plane::GetCenter() const
-    {
-    	return fCenter;
-    }
-
-    inline Plane::DimLessVec const& Plane::GetNormal() const
-    {
-    	return fNormal;
-    }
+  inline Point const& Plane::GetCenter() const { return fCenter; }
 
+  inline Plane::DimLessVec const& Plane::GetNormal() const { return fNormal; }
 
 } // namespace corsika
-
diff --git a/corsika/detail/framework/geometry/Sphere.inl b/corsika/detail/framework/geometry/Sphere.inl
index 68e10467c1e9bf048f6b117ee934812027ff8ef7..1f3735655bb68f8c34d50cd7a37701c972479eb6 100644
--- a/corsika/detail/framework/geometry/Sphere.inl
+++ b/corsika/detail/framework/geometry/Sphere.inl
@@ -16,21 +16,13 @@
 
 namespace corsika {
 
-    //! returns true if the Point p is within the sphere
-    bool Sphere::Contains(Point const& p) const
-    {
-      return fRadius * fRadius > (fCenter - p).squaredNorm();
-    }
+  //! returns true if the Point p is within the sphere
+  bool Sphere::Contains(Point const& p) const {
+    return fRadius * fRadius > (fCenter - p).squaredNorm();
+  }
 
-    const Point& Sphere::GetCenter() const
-    {
-    	return fCenter;
-    }
+  const Point& Sphere::GetCenter() const { return fCenter; }
 
-    units::si::LengthType Sphere::GetRadius() const
-    {
-    	return fRadius;
-    }
+  LengthType Sphere::GetRadius() const { return fRadius; }
 
 } // namespace corsika
-
diff --git a/corsika/detail/framework/geometry/Trajectory.inl b/corsika/detail/framework/geometry/Trajectory.inl
index 8a34d758daa2120bbea9081331a4cd184d1884f8..6937ab8e30520299f54a0362d178385e94526224 100644
--- a/corsika/detail/framework/geometry/Trajectory.inl
+++ b/corsika/detail/framework/geometry/Trajectory.inl
@@ -16,46 +16,37 @@
 
 namespace corsika {
 
-    template <typename T>
-    Point Trajectory<T>::GetPosition(double u) const
-    {
-    	return T::GetPosition(fTimeLength * u);
-    }
-
-    template <typename T>
-    corsika::units::si::TimeType Trajectory<T>::GetDuration() const
-    {
-    	return fTimeLength;
-    }
-
-    template <typename T>
-    corsika::units::si::LengthType Trajectory<T>::GetLength() const
-    {
-    	return GetDistance(fTimeLength);
-    }
-
-    template <typename T>
-    corsika::units::si::LengthType Trajectory<T>::GetDistance(corsika::units::si::TimeType t) const
-    {
-      assert(t <= fTimeLength);
-      assert(t >= 0 * corsika::units::si::second);
-      return T::ArcLength(0 * corsika::units::si::second, t);
-    }
-
-    template <typename T>
-    void Trajectory<T>::LimitEndTo(corsika::units::si::LengthType limit)
-    {
-      fTimeLength = T::TimeFromArclength(limit);
-    }
-
-    template <typename T>
-    auto Trajectory<T>::NormalizedDirection() const
-    {
-      static_assert(std::is_same_v<T, corsika::Line>);
-      return T::GetV0().normalized();
-    }
-
+  template <typename T>
+  Point Trajectory<T>::GetPosition(double u) const {
+    return T::GetPosition(fTimeLength * u);
+  }
+
+  template <typename T>
+  TimeType Trajectory<T>::GetDuration() const {
+    return fTimeLength;
+  }
+
+  template <typename T>
+  LengthType Trajectory<T>::GetLength() const {
+    return GetDistance(fTimeLength);
+  }
+
+  template <typename T>
+  LengthType Trajectory<T>::GetDistance(TimeType t) const {
+    assert(t <= fTimeLength);
+    assert(t >= 0 * second);
+    return T::ArcLength(0 * second, t);
+  }
+
+  template <typename T>
+  void Trajectory<T>::LimitEndTo(LengthType limit) {
+    fTimeLength = T::TimeFromArclength(limit);
+  }
+
+  template <typename T>
+  auto Trajectory<T>::NormalizedDirection() const {
+    static_assert(std::is_same_v<T, corsika::Line>);
+    return T::GetV0().normalized();
+  }
 
 } // namespace corsika
-
-
diff --git a/corsika/detail/framework/process/ProcessSequence.inl b/corsika/detail/framework/process/ProcessSequence.inl
new file mode 100644
index 0000000000000000000000000000000000000000..8492f3d0d924f01e580084a52b234934d7a3f270
--- /dev/null
+++ b/corsika/detail/framework/process/ProcessSequence.inl
@@ -0,0 +1,258 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/process/BaseProcess.hpp>
+#include <corsika/framework/process/BoundaryCrossingProcess.hpp>
+#include <corsika/framework/process/ContinuousProcess.hpp>
+#include <corsika/framework/process/DecayProcess.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
+#include <corsika/framework/process/SecondariesProcess.hpp>
+#include <corsika/framework/process/StackProcess.hpp>
+
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+namespace corsika {
+
+  template <typename T1, typename T2>
+  template <typename Particle, typename VTNType>
+  EProcessReturn ProcessSequence<T1, T2>::DoBoundaryCrossing(Particle& p,
+                                                             VTNType const& from,
+                                                             VTNType const& to) {
+    EProcessReturn ret = EProcessReturn::eOk;
+
+    if constexpr (std::is_base_of<BoundaryCrossingProcess<T1type>, T1type>::value ||
+                  t1ProcSeq) {
+      ret |= A.DoBoundaryCrossing(p, from, to);
+    }
+
+    if constexpr (std::is_base_of<BoundaryCrossingProcess<T2type>, T2type>::value ||
+                  t2ProcSeq) {
+      ret |= B.DoBoundaryCrossing(p, from, to);
+    }
+
+    return ret;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle, typename TTrack>
+  EProcessReturn ProcessSequence<T1, T2>::DoContinuous(TParticle& vP, TTrack& vT) {
+    EProcessReturn ret = EProcessReturn::eOk;
+    if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value ||
+                  t1ProcSeq) {
+
+      ret |= A.DoContinuous(vP, vT);
+    }
+    if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value ||
+                  t2ProcSeq) {
+      ret |= B.DoContinuous(vP, vT);
+    }
+    return ret;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TSecondaries>
+  EProcessReturn ProcessSequence<T1, T2>::DoSecondaries(TSecondaries& vS) {
+    EProcessReturn ret = EProcessReturn::eOk;
+    if constexpr (std::is_base_of<SecondariesProcess<T1type>, T1type>::value ||
+                  t1ProcSeq) {
+      ret |= A.DoSecondaries(vS);
+    }
+    if constexpr (std::is_base_of<SecondariesProcess<T2type>, T2type>::value ||
+                  t2ProcSeq) {
+      ret |= B.DoSecondaries(vS);
+    }
+    return ret;
+  }
+
+  template <typename T1, typename T2>
+  bool ProcessSequence<T1, T2>::CheckStep() {
+    bool ret = false;
+    if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) {
+      ret |= A.CheckStep();
+    }
+    if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) {
+      ret |= B.CheckStep();
+    }
+    return ret;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TStack>
+  EProcessReturn ProcessSequence<T1, T2>::DoStack(TStack& vS) {
+    EProcessReturn ret = EProcessReturn::eOk;
+    if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) {
+      if (A.CheckStep()) { ret |= A.DoStack(vS); }
+    }
+    if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) {
+      if (B.CheckStep()) { ret |= B.DoStack(vS); }
+    }
+    return ret;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle, typename TTrack>
+  LengthType ProcessSequence<T1, T2>::MaxStepLength(TParticle& vP, TTrack& vTrack) {
+    LengthType max_length = // if no other process in the sequence implements it
+        std::numeric_limits<double>::infinity() * meter;
+
+    if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value ||
+                  t1ProcSeq) {
+      LengthType const len = A.MaxStepLength(vP, vTrack);
+      max_length = std::min(max_length, len);
+    }
+    if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value ||
+                  t2ProcSeq) {
+      LengthType const len = B.MaxStepLength(vP, vTrack);
+      max_length = std::min(max_length, len);
+    }
+    return max_length;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle>
+  GrammageType ProcessSequence<T1, T2>::GetTotalInteractionLength(TParticle& vP) {
+    return 1. / GetInverseInteractionLength(vP);
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle>
+  InverseGrammageType ProcessSequence<T1, T2>::GetTotalInverseInteractionLength(
+      TParticle& vP) {
+    return GetInverseInteractionLength(vP);
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle>
+  InverseGrammageType ProcessSequence<T1, T2>::GetInverseInteractionLength(
+      TParticle& vP) {
+    InverseGrammageType tot = 0 * meter * meter / gram;
+
+    if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value ||
+                  t1ProcSeq || t1SwitchProc) {
+      tot += A.GetInverseInteractionLength(vP);
+    }
+    if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value ||
+                  t2ProcSeq || t2SwitchProc) {
+      tot += B.GetInverseInteractionLength(vP);
+    }
+    return tot;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle, typename TSecondaries>
+  EProcessReturn ProcessSequence<T1, T2>::SelectInteraction(
+      TParticle& vP, TSecondaries& vS, [[maybe_unused]] InverseGrammageType lambda_select,
+      InverseGrammageType& lambda_inv_count) {
+
+    if constexpr (t1ProcSeq || t1SwitchProc) {
+      // if A is a process sequence --> check inside
+      const EProcessReturn ret =
+          A.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
+      // if A did succeed, stop routine
+      if (ret != EProcessReturn::eOk) { return ret; }
+    } else if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value) {
+      // if this is not a ContinuousProcess --> evaluate probability
+      lambda_inv_count += A.GetInverseInteractionLength(vP);
+      // check if we should execute THIS process and then EXIT
+      if (lambda_select < lambda_inv_count) {
+        A.DoInteraction(vS);
+        return EProcessReturn::eInteracted;
+      }
+    } // end branch A
+
+    if constexpr (t2ProcSeq || t2SwitchProc) {
+      // if A is a process sequence --> check inside
+      const EProcessReturn ret =
+          B.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
+      // if A did succeed, stop routine
+      if (ret != EProcessReturn::eOk) { return ret; }
+    } else if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value) {
+      // if this is not a ContinuousProcess --> evaluate probability
+      lambda_inv_count += B.GetInverseInteractionLength(vP);
+      // check if we should execute THIS process and then EXIT
+      if (lambda_select < lambda_inv_count) {
+        B.DoInteraction(vS);
+        return EProcessReturn::eInteracted;
+      }
+    } // end branch A
+    return EProcessReturn::eOk;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle>
+  TimeType ProcessSequence<T1, T2>::GetTotalLifetime(TParticle& p) {
+    return 1. / GetInverseLifetime(p);
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle>
+  InverseTimeType ProcessSequence<T1, T2>::GetTotalInverseLifetime(TParticle& p) {
+    return GetInverseLifetime(p);
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle>
+  InverseTimeType ProcessSequence<T1, T2>::GetInverseLifetime(TParticle& p) {
+    InverseTimeType tot = 0 / second;
+
+    if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value || t1ProcSeq) {
+      tot += A.GetInverseLifetime(p);
+    }
+    if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value || t2ProcSeq) {
+      tot += B.GetInverseLifetime(p);
+    }
+    return tot;
+  }
+
+  template <typename T1, typename T2>
+  template <typename TParticle, typename TSecondaries>
+  EProcessReturn ProcessSequence<T1, T2>::SelectDecay(
+      TParticle& vP, TSecondaries& vS, [[maybe_unused]] InverseTimeType decay_select,
+      InverseTimeType& decay_inv_count) {
+    if constexpr (t1ProcSeq) {
+      // if A is a process sequence --> check inside
+      const EProcessReturn ret = A.SelectDecay(vP, vS, decay_select, decay_inv_count);
+      // if A did succeed, stop routine
+      if (ret != EProcessReturn::eOk) { return ret; }
+    } else if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value) {
+      // if this is not a ContinuousProcess --> evaluate probability
+      decay_inv_count += A.GetInverseLifetime(vP);
+      // check if we should execute THIS process and then EXIT
+      if (decay_select < decay_inv_count) { // more pedagogical: rndm_select <
+        // decay_inv_count / decay_inv_tot
+        A.DoDecay(vS);
+        return EProcessReturn::eDecayed;
+      }
+    } // end branch A
+
+    if constexpr (t2ProcSeq) {
+      // if A is a process sequence --> check inside
+      const EProcessReturn ret = B.SelectDecay(vP, vS, decay_select, decay_inv_count);
+      // if A did succeed, stop routine
+      if (ret != EProcessReturn::eOk) { return ret; }
+    } else if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value) {
+      // if this is not a ContinuousProcess --> evaluate probability
+      decay_inv_count += B.GetInverseLifetime(vP);
+      // check if we should execute THIS process and then EXIT
+      if (decay_select < decay_inv_count) {
+        B.DoDecay(vS);
+        return EProcessReturn::eDecayed;
+      }
+    } // end branch B
+    return EProcessReturn::eOk;
+  }
+
+} // namespace corsika
diff --git a/corsika/detail/framework/sequence/ProcessSequence.inl b/corsika/detail/framework/sequence/ProcessSequence.inl
deleted file mode 100644
index 60295fd8b9be57b425df17165c8259f9cbb2ad9b..0000000000000000000000000000000000000000
--- a/corsika/detail/framework/sequence/ProcessSequence.inl
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
- *
- * This software is distributed under the terms of the GNU General Public
- * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
- * the license.
- */
-
-#pragma once
-
-#include <corsika/framework/sequence/BaseProcess.hpp>
-#include <corsika/framework/sequence/BoundaryCrossingProcess.hpp>
-#include <corsika/framework/sequence/DecayProcess.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
-#include <corsika/framework/sequence/StackProcess.hpp>
-#include <cmath>
-#include <limits>
-#include <type_traits>
-#include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/ContinuousProcess.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp>
-#include <corsika/framework/sequence/SecondariesProcess.hpp>
-
-namespace corsika {
-
-
-
-	template <typename T1, typename T2>
-	template <typename Particle, typename VTNType>
-	EProcessReturn ProcessSequence<T1, T2>::DoBoundaryCrossing(Particle& p, VTNType const& from,
-			VTNType const& to) {
-		EProcessReturn ret = EProcessReturn::eOk;
-
-		if constexpr (std::is_base_of<BoundaryCrossingProcess<T1type>, T1type>::value ||
-				t1ProcSeq) {
-			ret |= A.DoBoundaryCrossing(p, from, to);
-		}
-
-		if constexpr (std::is_base_of<BoundaryCrossingProcess<T2type>, T2type>::value ||
-				t2ProcSeq) {
-			ret |= B.DoBoundaryCrossing(p, from, to);
-		}
-
-		return ret;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle, typename TTrack>
-	EProcessReturn ProcessSequence<T1, T2>::DoContinuous(TParticle& vP, TTrack& vT) {
-		EProcessReturn ret = EProcessReturn::eOk;
-		if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value || t1ProcSeq) {
-
-			ret |= A.DoContinuous(vP, vT);
-		}
-		if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value || t2ProcSeq) {
-			ret |= B.DoContinuous(vP, vT);
-		}
-		return ret;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TSecondaries>
-	EProcessReturn ProcessSequence<T1, T2>::DoSecondaries(TSecondaries& vS) {
-		EProcessReturn ret = EProcessReturn::eOk;
-		if constexpr (std::is_base_of<SecondariesProcess<T1type>, T1type>::value || t1ProcSeq) {
-			ret |= A.DoSecondaries(vS);
-		}
-		if constexpr (std::is_base_of<SecondariesProcess<T2type>, T2type>::value || t2ProcSeq) {
-			ret |= B.DoSecondaries(vS);
-		}
-		return ret;
-	}
-
-	template <typename T1, typename T2>
-	bool ProcessSequence<T1, T2>::CheckStep() {
-		bool ret = false;
-		if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) {
-			ret |= A.CheckStep();
-		}
-		if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) {
-			ret |= B.CheckStep();
-		}
-		return ret;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TStack>
-	EProcessReturn ProcessSequence<T1, T2>::DoStack(TStack& vS) {
-		EProcessReturn ret = EProcessReturn::eOk;
-		if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) {
-			if (A.CheckStep()) { ret |= A.DoStack(vS); }
-		}
-		if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) {
-			if (B.CheckStep()) { ret |= B.DoStack(vS); }
-		}
-		return ret;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle, typename TTrack>
-	corsika::units::si::LengthType ProcessSequence<T1, T2>::MaxStepLength(TParticle& vP, TTrack& vTrack) {
-		corsika::units::si::LengthType
-		max_length = // if no other process in the sequence implements it
-		std::numeric_limits<double>::infinity() * corsika::units::si::meter;
-
-		if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value || t1ProcSeq) {
-			corsika::units::si::LengthType const len = A.MaxStepLength(vP, vTrack);
-			max_length = std::min(max_length, len);
-		}
-		if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value || t2ProcSeq) {
-			corsika::units::si::LengthType const len = B.MaxStepLength(vP, vTrack);
-			max_length = std::min(max_length, len);
-		}
-		return max_length;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle>
-	corsika::units::si::GrammageType ProcessSequence<T1, T2>::GetTotalInteractionLength(TParticle& vP) {
-		return 1. / GetInverseInteractionLength(vP);
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle>
-	corsika::units::si::InverseGrammageType ProcessSequence<T1, T2>::GetTotalInverseInteractionLength(
-			TParticle& vP) {
-		return GetInverseInteractionLength(vP);
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle>
-	corsika::units::si::InverseGrammageType ProcessSequence<T1, T2>::GetInverseInteractionLength(TParticle& vP) {
-		corsika::units::si::InverseGrammageType tot = 0 * corsika::units::si::meter * corsika::units::si::meter / corsika::units::si::gram;
-
-		if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value || t1ProcSeq ||
-				t1SwitchProc) {
-			tot += A.GetInverseInteractionLength(vP);
-		}
-		if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value || t2ProcSeq ||
-				t2SwitchProc) {
-			tot += B.GetInverseInteractionLength(vP);
-		}
-		return tot;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle, typename TSecondaries>
-	EProcessReturn ProcessSequence<T1, T2>::SelectInteraction(
-			TParticle& vP, TSecondaries& vS,
-			[[maybe_unused]] corsika::units::si::InverseGrammageType lambda_select,
-			corsika::units::si::InverseGrammageType& lambda_inv_count)
-	{
-
-		if constexpr (t1ProcSeq || t1SwitchProc) {
-			// if A is a process sequence --> check inside
-			const EProcessReturn ret =
-					A.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
-			// if A did succeed, stop routine
-			if (ret != EProcessReturn::eOk) { return ret; }
-		} else if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value ) {
-			// if this is not a ContinuousProcess --> evaluate probability
-			lambda_inv_count += A.GetInverseInteractionLength(vP);
-			// check if we should execute THIS process and then EXIT
-			if (lambda_select < lambda_inv_count) {
-				A.DoInteraction(vS);
-				return EProcessReturn::eInteracted;
-			}
-		} // end branch A
-
-		if constexpr (t2ProcSeq || t2SwitchProc) {
-			// if A is a process sequence --> check inside
-			const EProcessReturn ret =
-					B.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
-			// if A did succeed, stop routine
-			if (ret != EProcessReturn::eOk) { return ret; }
-		} else if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value) {
-			// if this is not a ContinuousProcess --> evaluate probability
-			lambda_inv_count += B.GetInverseInteractionLength(vP);
-			// check if we should execute THIS process and then EXIT
-			if (lambda_select < lambda_inv_count) {
-				B.DoInteraction(vS);
-				return EProcessReturn::eInteracted;
-			}
-		} // end branch A
-		return EProcessReturn::eOk;
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle>
-	corsika::units::si::TimeType ProcessSequence<T1, T2>::GetTotalLifetime(TParticle& p) {
-		return 1. / GetInverseLifetime(p);
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle>
-	corsika::units::si::InverseTimeType ProcessSequence<T1, T2>::GetTotalInverseLifetime(TParticle& p) {
-		return GetInverseLifetime(p);
-	}
-
-	template <typename T1, typename T2>
-	template <typename TParticle>
-	corsika::units::si::InverseTimeType ProcessSequence<T1, T2>::GetInverseLifetime(TParticle& p) {
-		corsika::units::si::InverseTimeType tot = 0 / corsika::units::si::second;
-
-		if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value || t1ProcSeq) {
-			tot += A.GetInverseLifetime(p);
-		}
-		if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value || t2ProcSeq) {
-			tot += B.GetInverseLifetime(p);
-		}
-		return tot;
-	}
-
-
-	template <typename T1, typename T2>
-	template <typename TParticle, typename TSecondaries>
-	EProcessReturn ProcessSequence<T1, T2>::SelectDecay(
-			TParticle& vP, TSecondaries& vS,
-			[[maybe_unused]] corsika::units::si::InverseTimeType decay_select,
-			corsika::units::si::InverseTimeType& decay_inv_count) {
-		if constexpr (t1ProcSeq) {
-			// if A is a process sequence --> check inside
-			const EProcessReturn ret = A.SelectDecay(vP, vS, decay_select, decay_inv_count);
-			// if A did succeed, stop routine
-			if (ret != EProcessReturn::eOk) { return ret; }
-		} else if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value) {
-			// if this is not a ContinuousProcess --> evaluate probability
-			decay_inv_count += A.GetInverseLifetime(vP);
-			// check if we should execute THIS process and then EXIT
-			if (decay_select < decay_inv_count) { // more pedagogical: rndm_select <
-				// decay_inv_count / decay_inv_tot
-				A.DoDecay(vS);
-				return EProcessReturn::eDecayed;
-			}
-		} // end branch A
-
-		if constexpr (t2ProcSeq) {
-			// if A is a process sequence --> check inside
-			const EProcessReturn ret = B.SelectDecay(vP, vS, decay_select, decay_inv_count);
-			// if A did succeed, stop routine
-			if (ret != EProcessReturn::eOk) { return ret; }
-		} else if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value) {
-			// if this is not a ContinuousProcess --> evaluate probability
-			decay_inv_count += B.GetInverseLifetime(vP);
-			// check if we should execute THIS process and then EXIT
-			if (decay_select < decay_inv_count) {
-				B.DoDecay(vS);
-				return EProcessReturn::eDecayed;
-			}
-		} // end branch B
-		return EProcessReturn::eOk;
-	}
-
-
-} // namespace corsika
-
diff --git a/corsika/detail/framework/utility/COMBoost.inl b/corsika/detail/framework/utility/COMBoost.inl
index f0e9f9e4bd525738f0e42a30e070642246a0a3ca..8a87616bc0eb03772c9eb806157cd1d7427d2d7e 100644
--- a/corsika/detail/framework/utility/COMBoost.inl
+++ b/corsika/detail/framework/utility/COMBoost.inl
@@ -24,7 +24,6 @@ namespace corsika {
   //! transforms a 4-momentum from lab frame to the center-of-mass frame
   template <typename FourVector>
   inline FourVector COMBoost::toCoM(const FourVector& p) const {
-    using namespace corsika::units::si;
     auto pComponents = p.GetSpaceLikeComponents().GetComponents(fCS);
     Eigen::Vector3d eVecRotated = fRotation * pComponents.eVector;
     Eigen::Vector2d lab;
@@ -37,14 +36,12 @@ namespace corsika {
 
     eVecRotated(2) = boostedZ(1) * (1_GeV).magnitude();
 
-    return FourVector(
-        E_CoM, corsika::Vector<corsika::units::si::hepmomentum_d>(fCS, eVecRotated));
+    return FourVector(E_CoM, corsika::Vector<hepmomentum_d>(fCS, eVecRotated));
   }
 
   //! transforms a 4-momentum from the center-of-mass frame back to lab frame
   template <typename FourVector>
   inline FourVector COMBoost::fromCoM(const FourVector& p) const {
-    using namespace corsika::units::si;
     Eigen::Vector2d com;
     com << (p.GetTimeLikeComponent() * (1 / 1_GeV)),
         (p.GetSpaceLikeComponents().GetComponents().eVector(2) * (1 / 1_GeV).magnitude());
@@ -71,9 +68,8 @@ namespace corsika {
   }
 
   inline COMBoost::COMBoost(
-      FourVector<corsika::units::si::HEPEnergyType,
-                 Vector<corsika::units::si::hepmomentum_d>> const& Pprojectile,
-      const corsika::units::si::HEPMassType massTarget)
+      FourVector<HEPEnergyType, Vector<hepmomentum_d>> const& Pprojectile,
+      const HEPMassType massTarget)
       : fCS(Pprojectile.GetSpaceLikeComponents().GetCoordinateSystem()) {
     auto const pProjectile = Pprojectile.GetSpaceLikeComponents();
     auto const pProjNorm = pProjectile.norm();
diff --git a/corsika/detail/media/BaseExponential.inl b/corsika/detail/media/BaseExponential.inl
index c4c51cb77a40146e367b19c0b4c1134f0c331874..4e954264e6ede71b74560b9c9c7051e0ed618afd 100644
--- a/corsika/detail/media/BaseExponential.inl
+++ b/corsika/detail/media/BaseExponential.inl
@@ -14,50 +14,45 @@
 
 namespace corsika {
 
-
   template <class TDerived>
-    auto const& BaseExponential<TDerived>::GetImplementation() const 
-{ return *static_cast<TDerived const*>(this); }
+  auto const& BaseExponential<TDerived>::GetImplementation() const {
+    return *static_cast<TDerived const*>(this);
+  }
 
   template <class TDerived>
-    units::si::GrammageType BaseExponential<TDerived>::IntegratedGrammage(
-        Trajectory<Line> const& vLine,
-		units::si::LengthType vL,
-        Vector<units::si::dimensionless_d> const& vAxis) const {
-      if (vL == units::si::LengthType::zero()) { return units::si::GrammageType::zero(); }
-
-      auto const uDotA = vLine.NormalizedDirection().dot(vAxis).magnitude();
-      auto const rhoStart = GetImplementation().GetMassDensity(vLine.GetR0());
-
-      if (uDotA == 0) {
-        return vL * rhoStart;
-      } else {
-        return rhoStart * (fLambda / uDotA) * (exp(uDotA * vL * fInvLambda) - 1);
-      }
+  GrammageType BaseExponential<TDerived>::IntegratedGrammage(
+      Trajectory<Line> const& vLine, LengthType vL,
+      Vector<dimensionless_d> const& vAxis) const {
+    if (vL == LengthType::zero()) { return GrammageType::zero(); }
+
+    auto const uDotA = vLine.NormalizedDirection().dot(vAxis).magnitude();
+    auto const rhoStart = GetImplementation().GetMassDensity(vLine.GetR0());
+
+    if (uDotA == 0) {
+      return vL * rhoStart;
+    } else {
+      return rhoStart * (fLambda / uDotA) * (exp(uDotA * vL * fInvLambda) - 1);
     }
+  }
 
   template <class TDerived>
-    units::si::LengthType BaseExponential<TDerived>::ArclengthFromGrammage(
-        Trajectory<Line> const& vLine,
-        units::si::GrammageType vGrammage,
-        Vector<units::si::dimensionless_d> const& vAxis) const {
-      auto const uDotA = vLine.NormalizedDirection().dot(vAxis).magnitude();
-      auto const rhoStart = GetImplementation().GetMassDensity(vLine.GetR0());
-
-      if (uDotA == 0) {
-        return vGrammage / rhoStart;
+  LengthType BaseExponential<TDerived>::ArclengthFromGrammage(
+      Trajectory<Line> const& vLine, GrammageType vGrammage,
+      Vector<dimensionless_d> const& vAxis) const {
+    auto const uDotA = vLine.NormalizedDirection().dot(vAxis).magnitude();
+    auto const rhoStart = GetImplementation().GetMassDensity(vLine.GetR0());
+
+    if (uDotA == 0) {
+      return vGrammage / rhoStart;
+    } else {
+      auto const logArg = vGrammage * fInvLambda * uDotA / rhoStart + 1;
+      if (logArg > 0) {
+        return fLambda / uDotA * log(logArg);
       } else {
-        auto const logArg = vGrammage * fInvLambda * uDotA / rhoStart + 1;
-        if (logArg > 0) {
-          return fLambda / uDotA * log(logArg);
-        } else {
-          return std::numeric_limits<typename decltype(
-                     vGrammage)::value_type>::infinity() *
-                 units::si::meter;
-        }
+        return std::numeric_limits<typename decltype(vGrammage)::value_type>::infinity() *
+               meter;
       }
     }
-
+  }
 
 } // namespace corsika
-
diff --git a/corsika/detail/media/FlatExponential.inl b/corsika/detail/media/FlatExponential.inl
index 24f66e557983d8db5ad5679920760d39824c5d3f..31453d7b9d47f7918214be9678a74df1949d12d0 100644
--- a/corsika/detail/media/FlatExponential.inl
+++ b/corsika/detail/media/FlatExponential.inl
@@ -15,7 +15,7 @@
 namespace corsika {
 
   template <class T>
-  units::si::MassDensityType FlatExponential<T>::GetMassDensity(Point const& vP) const {
+  MassDensityType FlatExponential<T>::GetMassDensity(Point const& vP) const {
     return Base::fRho0 * exp(Base::fInvLambda * (vP - Base::fP0).dot(fAxis));
   }
 
@@ -25,14 +25,14 @@ namespace corsika {
   }
 
   template <class T>
-  units::si::GrammageType FlatExponential<T>::IntegratedGrammage(
-      Trajectory<Line> const& vLine, units::si::LengthType vTo) const {
+  GrammageType FlatExponential<T>::IntegratedGrammage(Trajectory<Line> const& vLine,
+                                                      LengthType vTo) const {
     return Base::IntegratedGrammage(vLine, vTo, fAxis);
   }
 
   template <class T>
-  units::si::LengthType FlatExponential<T>::ArclengthFromGrammage(
-      Trajectory<Line> const& vLine, units::si::GrammageType vGrammage) const {
+  LengthType FlatExponential<T>::ArclengthFromGrammage(Trajectory<Line> const& vLine,
+                                                       GrammageType vGrammage) const {
     return Base::ArclengthFromGrammage(vLine, vGrammage, fAxis);
   }
 
diff --git a/corsika/detail/media/LayeredSphericalAtmosphereBuilder.inl b/corsika/detail/media/LayeredSphericalAtmosphereBuilder.inl
index be0781236549f4958cb1e975c50d07fd5afc46ed..c3b4c7fe64ec803a295a22b379b21716b2c5a3c5 100644
--- a/corsika/detail/media/LayeredSphericalAtmosphereBuilder.inl
+++ b/corsika/detail/media/LayeredSphericalAtmosphereBuilder.inl
@@ -15,73 +15,71 @@
 
 namespace corsika {
 
-void LayeredSphericalAtmosphereBuilder::checkRadius(units::si::LengthType r) const {
-  if (r <= previousRadius_) {
-    throw std::runtime_error("radius must be greater than previous");
+  void LayeredSphericalAtmosphereBuilder::checkRadius(LengthType r) const {
+    if (r <= previousRadius_) {
+      throw std::runtime_error("radius must be greater than previous");
+    }
   }
-}
 
-void LayeredSphericalAtmosphereBuilder::setNuclearComposition(
-    NuclearComposition composition) {
-  composition_ = std::make_unique<NuclearComposition>(composition);
-}
-
-void LayeredSphericalAtmosphereBuilder::addExponentialLayer(
-    units::si::GrammageType b, units::si::LengthType c,
-    units::si::LengthType upperBoundary) {
-  auto const radius = seaLevel_ + upperBoundary;
-  checkRadius(radius);
-  previousRadius_ = radius;
-
-  auto node = std::make_unique<VolumeTreeNode<IMediumModel>>(
-      std::make_unique<Sphere>(center_, radius));
+  void LayeredSphericalAtmosphereBuilder::setNuclearComposition(
+      NuclearComposition composition) {
+    composition_ = std::make_unique<NuclearComposition>(composition);
+  }
 
-  auto const rho0 = b / c;
-  std::cout << "rho0 = " << rho0 << ", c = " << c << std::endl;
+  void LayeredSphericalAtmosphereBuilder::addExponentialLayer(GrammageType b,
+                                                              LengthType c,
+                                                              LengthType upperBoundary) {
+    auto const radius = seaLevel_ + upperBoundary;
+    checkRadius(radius);
+    previousRadius_ = radius;
 
-  node->SetModelProperties<SlidingPlanarExponential<IMediumModel>>(
-      center_, rho0, -c, *composition_, seaLevel_);
+    auto node = std::make_unique<VolumeTreeNode<IMediumModel>>(
+        std::make_unique<Sphere>(center_, radius));
 
-  layers_.push(std::move(node));
-}
+    auto const rho0 = b / c;
+    std::cout << "rho0 = " << rho0 << ", c = " << c << std::endl;
 
-void LayeredSphericalAtmosphereBuilder::addLinearLayer(
-    units::si::LengthType c, units::si::LengthType upperBoundary) {
-  using namespace units::si;
+    node->SetModelProperties<SlidingPlanarExponential<IMediumModel>>(
+        center_, rho0, -c, *composition_, seaLevel_);
 
-  auto const radius = seaLevel_ + upperBoundary;
-  checkRadius(radius);
-  previousRadius_ = radius;
+    layers_.push(std::move(node));
+  }
 
-  units::si::GrammageType constexpr b = 1 * 1_g / (1_cm * 1_cm);
-  auto const rho0 = b / c;
+  void LayeredSphericalAtmosphereBuilder::addLinearLayer(LengthType c,
+                                                         LengthType upperBoundary) {
+    auto const radius = seaLevel_ + upperBoundary;
+    checkRadius(radius);
+    previousRadius_ = radius;
 
-  std::cout << "rho0 = " << rho0;
+    GrammageType constexpr b = 1 * 1_g / (1_cm * 1_cm);
+    auto const rho0 = b / c;
 
-  auto node = std::make_unique<VolumeTreeNode<IMediumModel>>(
-      std::make_unique<Sphere>(center_, radius));
-  node->SetModelProperties<HomogeneousMedium<IMediumModel>>(rho0, *composition_);
+    std::cout << "rho0 = " << rho0;
 
-  layers_.push(std::move(node));
-}
+    auto node = std::make_unique<VolumeTreeNode<IMediumModel>>(
+        std::make_unique<Sphere>(center_, radius));
+    node->SetModelProperties<HomogeneousMedium<IMediumModel>>(rho0, *composition_);
 
-Environment<IMediumModel> LayeredSphericalAtmosphereBuilder::assemble() {
-  Environment<IMediumModel> env;
-  assemble(env);
-  return env;
-}
+    layers_.push(std::move(node));
+  }
 
-void LayeredSphericalAtmosphereBuilder::assemble(Environment<IMediumModel>& env) {
-  auto& universe = env.GetUniverse();
-  auto* outmost = universe.get();
+  Environment<IMediumModel> LayeredSphericalAtmosphereBuilder::assemble() {
+    Environment<IMediumModel> env;
+    assemble(env);
+    return env;
+  }
 
-  while (!layers_.empty()) {
-    auto l = std::move(layers_.top());
-    auto* tmp = l.get();
-    outmost->AddChild(std::move(l));
-    layers_.pop();
-    outmost = tmp;
+  void LayeredSphericalAtmosphereBuilder::assemble(Environment<IMediumModel>& env) {
+    auto& universe = env.GetUniverse();
+    auto* outmost = universe.get();
+
+    while (!layers_.empty()) {
+      auto l = std::move(layers_.top());
+      auto* tmp = l.get();
+      outmost->AddChild(std::move(l));
+      layers_.pop();
+      outmost = tmp;
+    }
   }
-}
 
 } // namespace corsika
diff --git a/corsika/detail/media/LinearApproximationIntegrator.inl b/corsika/detail/media/LinearApproximationIntegrator.inl
index 77766a6d9a4f3e64b85064f79cf5055984cfd407..324bdbb96794e27edfe19808edbaf26341bde640 100644
--- a/corsika/detail/media/LinearApproximationIntegrator.inl
+++ b/corsika/detail/media/LinearApproximationIntegrator.inl
@@ -24,7 +24,7 @@ namespace corsika {
    template <class TDerived>
     auto LinearApproximationIntegrator<TDerived>::IntegrateGrammage(
         corsika::Trajectory<corsika::Line> const& line,
-        corsika::units::si::LengthType length) const {
+        LengthType length) const {
       auto const c0 = GetImplementation().EvaluateAt(line.GetPosition(0));
       auto const c1 = GetImplementation().fRho.FirstDerivative(
           line.GetPosition(0), line.NormalizedDirection());
@@ -34,7 +34,7 @@ namespace corsika {
    template <class TDerived>
     auto LinearApproximationIntegrator<TDerived>::ArclengthFromGrammage(
         corsika::Trajectory<corsika::Line> const& line,
-        corsika::units::si::GrammageType grammage) const {
+        GrammageType grammage) const {
       auto const c0 = GetImplementation().fRho(line.GetPosition(0));
       auto const c1 = GetImplementation().fRho.FirstDerivative(
           line.GetPosition(0), line.NormalizedDirection());
@@ -45,7 +45,6 @@ namespace corsika {
    template <class TDerived>
     auto LinearApproximationIntegrator<TDerived>::MaximumLength(corsika::Trajectory<corsika::Line> const& line,
                        [[maybe_unused]] double relError) const {
-      using namespace corsika::units::si;
       [[maybe_unused]] auto const c1 = GetImplementation().fRho.SecondDerivative(
           line.GetPosition(0), line.NormalizedDirection());
 
diff --git a/corsika/detail/media/SlidingPlanarExponential.inl b/corsika/detail/media/SlidingPlanarExponential.inl
index 224826efc36937facb55c5a9c3829ffdfc579411..61043f072a89a75795af728170b76781884c8aa8 100644
--- a/corsika/detail/media/SlidingPlanarExponential.inl
+++ b/corsika/detail/media/SlidingPlanarExponential.inl
@@ -15,22 +15,21 @@
 namespace corsika {
 
   template <class T>
-  units::si::MassDensityType SlidingPlanarExponential<T>::GetMassDensity(
-      Point const& p) const {
+  MassDensityType SlidingPlanarExponential<T>::GetMassDensity(Point const& p) const {
     auto const height = (p - Base::fP0).norm() - referenceHeight_;
     return Base::fRho0 * exp(Base::fInvLambda * height);
   }
 
   template <class T>
-  units::si::GrammageType SlidingPlanarExponential<T>::IntegratedGrammage(
-      Trajectory<Line> const& line, units::si::LengthType l) const {
+  GrammageType SlidingPlanarExponential<T>::IntegratedGrammage(
+      Trajectory<Line> const& line, LengthType l) const {
     auto const axis = (line.GetR0() - Base::fP0).normalized();
     return Base::IntegratedGrammage(line, l, axis);
   }
 
   template <class T>
-  units::si::LengthType SlidingPlanarExponential<T>::ArclengthFromGrammage(
-      Trajectory<Line> const& line, units::si::GrammageType grammage) const {
+  LengthType SlidingPlanarExponential<T>::ArclengthFromGrammage(
+      Trajectory<Line> const& line, GrammageType grammage) const {
     auto const axis = (line.GetR0() - Base::fP0).normalized();
     return Base::ArclengthFromGrammage(line, grammage, axis);
   }
diff --git a/corsika/detail/media/Universe.inl b/corsika/detail/media/Universe.inl
index c48d97b887c2b8a35c3c081612c0a329d928aa28..e54d4715ae9a7c512eea97e64540c3202e3036ef 100644
--- a/corsika/detail/media/Universe.inl
+++ b/corsika/detail/media/Universe.inl
@@ -15,10 +15,8 @@
 namespace corsika {
 
   Universe::Universe(corsika::CoordinateSystem const& pCS)
-      : corsika::Sphere(
-            corsika::Point{pCS, 0 * corsika::units::si::meter,
-                           0 * corsika::units::si::meter, 0 * corsika::units::si::meter},
-            corsika::units::si::meter * std::numeric_limits<double>::infinity()) {}
+      : corsika::Sphere(corsika::Point{pCS, 0 * meter, 0 * meter, 0 * meter},
+                        meter * std::numeric_limits<double>::infinity()) {}
 
   bool Universe::Contains(corsika::Point const&) const { return true; }
 
diff --git a/corsika/detail/modules/hadronic_elastic_model/HadronicElasticModel.inl b/corsika/detail/modules/HadronicElasticModel.inl
similarity index 75%
rename from corsika/detail/modules/hadronic_elastic_model/HadronicElasticModel.inl
rename to corsika/detail/modules/HadronicElasticModel.inl
index 9d6dd4f074fd6ec1bd63d104a310c6c64317964d..ed3009ef4d639f9a6cb96e6d0d33dcc79e41cf5f 100644
--- a/corsika/detail/modules/hadronic_elastic_model/HadronicElasticModel.inl
+++ b/corsika/detail/modules/HadronicElasticModel.inl
@@ -10,7 +10,7 @@
 
 #pragma once
 
-#include <corsika/modules/hadronic_elastic_model/HadronicElasticModel.hpp>
+#include <corsika/modules/HadronicElasticModel.hpp>
 
 #include <corsika/media/Environment.hpp>
 #include <corsika/media/NuclearComposition.hpp>
@@ -23,20 +23,17 @@
 #include <iomanip>
 #include <iostream>
 
-
 namespace corsika::hadronic_elastic_model {
 
   void HadronicElasticInteraction::Init() {}
 
-  HadronicElasticInteraction::HadronicElasticInteraction(units::si::CrossSectionType x,
-                                                         units::si::CrossSectionType y)
+  HadronicElasticInteraction::HadronicElasticInteraction(CrossSectionType x,
+                                                         CrossSectionType y)
       : fX(x)
       , fY(y) {}
 
   template <>
-  units::si::GrammageType HadronicElasticInteraction::GetInteractionLength(
-      SetupParticle const& p) {
-    using namespace units::si;
+  GrammageType HadronicElasticInteraction::GetInteractionLength(SetupParticle const& p) {
     if (p.GetPID() == particles::Code::Proton) {
       auto const* currentNode = p.GetNode();
       auto const& mediumComposition =
@@ -67,7 +64,7 @@ namespace corsika::hadronic_elastic_model {
       auto const avgTargetMassNumber = mediumComposition.GetAverageMassNumber();
 
       GrammageType const interactionLength =
-          avgTargetMassNumber * units::constants::u / avgCrossSection;
+          avgTargetMassNumber * constants::u / avgCrossSection;
 
       return interactionLength;
     } else {
@@ -79,14 +76,11 @@ namespace corsika::hadronic_elastic_model {
   corsika::EProcessReturn HadronicElasticInteraction::DoInteraction(TParticle& p) {
     if (p.GetPID() != particles::Code::Proton) { return process::EProcessReturn::eOk; }
 
-    using namespace units::si;
-    using namespace units::constants;
-
     const auto* currentNode = p.GetNode();
     const auto& composition = currentNode->GetModelProperties().GetNuclearComposition();
     const auto& components = composition.GetComponents();
 
-    std::vector<units::si::CrossSectionType> cross_section_of_components(
+    std::vector<CrossSectionType> cross_section_of_components(
         composition.GetComponents().size());
 
     auto const projectileMomentum = p.GetMomentum();
@@ -95,7 +89,7 @@ namespace corsika::hadronic_elastic_model {
 
     for (size_t i = 0; i < components.size(); ++i) {
       auto const targetMass = corsika::GetMass(components[i]);
-      auto const s = units::si::detail::static_pow<2>(projectileEnergy + targetMass) -
+      auto const s = detail::static_pow<2>(projectileEnergy + targetMass) -
                      projectileMomentumSquaredNorm;
       cross_section_of_components[i] = CrossSection(s);
     }
@@ -108,7 +102,7 @@ namespace corsika::hadronic_elastic_model {
 
     geometry::FourVector const projectileLab(projectileEnergy, projectileMomentum);
     geometry::FourVector const targetLab(
-        targetMass, corsika::Vector<units::si::hepmomentum_d>(
+        targetMass, corsika::Vector<hepmomentum_d>(
                         projectileMomentum.GetCoordinateSystem(), {0_eV, 0_eV, 0_eV}));
     utl::COMBoost const boost(projectileLab, targetMass);
 
@@ -123,7 +117,7 @@ namespace corsika::hadronic_elastic_model {
     auto const eTargetCoM = targetCoM.GetTimeLikeComponent();
 
     auto const sqrtS = eProjectileCoM + eTargetCoM;
-    auto const s = units::si::detail::static_pow<2>(sqrtS);
+    auto const s = detail::static_pow<2>(sqrtS);
 
     auto const B = this->B(s);
     std::cout << B << std::endl;
@@ -143,26 +137,26 @@ namespace corsika::hadronic_elastic_model {
       return absT;
     }();
 
-    std::cout << "HadronicElasticInteraction: s = " << s * invGeVsq
-              << " GeV²; absT = " << absT * invGeVsq
-              << " GeV² (max./GeV² = " << 4 * invGeVsq * projectileMomentumSquaredNorm
+    std::cout << "HadronicElasticInteraction: s = " << s * constants::invGeVsq
+              << " GeV²; absT = " << absT * constants::invGeVsq
+              << " GeV² (max./GeV² = " << 4 * constants::invGeVsq * projectileMomentumSquaredNorm
               << ')' << std::endl;
 
     auto const theta = 2 * asin(sqrt(absT / (4 * pProjectileCoMSqNorm)));
     auto const phi = phiDist(fRNG);
 
-    auto const projectileScatteredLab = boost.fromCoM(
-        corsika::FourVector<HEPEnergyType, corsika::Vector<hepmomentum_d>>(
+    auto const projectileScatteredLab =
+        boost.fromCoM(corsika::FourVector<HEPEnergyType, corsika::Vector<hepmomentum_d>>(
             eProjectileCoM,
             corsika::Vector<hepmomentum_d>(projectileMomentum.GetCoordinateSystem(),
-                                            {pProjectileCoMNorm * sin(theta) * cos(phi),
-                                             pProjectileCoMNorm * sin(theta) * sin(phi),
-                                             pProjectileCoMNorm * cos(theta)})));
+                                           {pProjectileCoMNorm * sin(theta) * cos(phi),
+                                            pProjectileCoMNorm * sin(theta) * sin(phi),
+                                            pProjectileCoMNorm * cos(theta)})));
 
     p.SetMomentum(projectileScatteredLab.GetSpaceLikeComponents());
     p.SetEnergy(
         sqrt(projectileScatteredLab.GetSpaceLikeComponents().squaredNorm() +
-             units::si::detail::static_pow<2>(particles::GetMass(
+             detail::static_pow<2>(particles::GetMass(
                  p.GetPID())))); // Don't use energy from boost. It can be smaller than
                                  // the momentum due to limited numerical accuracy.
 
@@ -170,27 +164,24 @@ namespace corsika::hadronic_elastic_model {
   }
 
   HadronicElasticInteraction::inveV2 HadronicElasticInteraction::B(eV2 s) const {
-    using namespace units::constants;
     auto constexpr b_p = 2.3;
     auto const result =
-        (2 * b_p + 2 * b_p + 4 * pow(s * invGeVsq, gfEpsilon) - 4.2) * invGeVsq;
+        (2 * b_p + 2 * b_p + 4 * pow(s * constants::invGeVsq, gfEpsilon) - 4.2) * constants::invGeVsq;
     std::cout << "B(" << s << ") = " << result / invGeVsq << " GeV¯²" << std::endl;
     return result;
   }
 
-  units::si::CrossSectionType HadronicElasticInteraction::CrossSection(
+  CrossSectionType HadronicElasticInteraction::CrossSection(
       SquaredHEPEnergyType s) const {
-    using namespace units::si;
-    using namespace units::constants;
     // assuming every target behaves like a proton, fX and fY are universal
     CrossSectionType const sigmaTotal =
-        fX * pow(s * invGeVsq, gfEpsilon) + fY * pow(s * invGeVsq, -gfEta);
+        fX * pow(s * constants::invGeVsq, gfEpsilon) + fY * pow(s * constants::invGeVsq, -gfEta);
 
     // according to Schuler & Sjöstrand, PRD 49, 2257 (1994)
     // (we ignore rho because rho^2 is just ~2 %)
     auto const sigmaElastic =
-        units::si::detail::static_pow<2>(sigmaTotal) /
-        (16 * M_PI * ConvertHEPToSI<CrossSectionType::dimension_type>(B(s)));
+        detail::static_pow<2>(sigmaTotal) /
+        (16 * constants::pi * ConvertHEPToSI<CrossSectionType::dimension_type>(B(s)));
 
     std::cout << "HEM sigmaTot = " << sigmaTotal / 1_mb << " mb" << std::endl;
     std::cout << "HEM sigmaElastic = " << sigmaElastic / 1_mb << " mb" << std::endl;
@@ -198,4 +189,3 @@ namespace corsika::hadronic_elastic_model {
   }
 
 } // namespace corsika::hadronic_elastic_model
-
diff --git a/corsika/detail/modules/null_model/NullModel.inl b/corsika/detail/modules/NullModel.inl
similarity index 73%
rename from corsika/detail/modules/null_model/NullModel.inl
rename to corsika/detail/modules/NullModel.inl
index 87115f4e5748ca959e915d46d67e1423abb0a96a..98a7bed800ea5b33309713e5ec87ab7d681eaf6c 100644
--- a/corsika/detail/modules/null_model/NullModel.inl
+++ b/corsika/detail/modules/NullModel.inl
@@ -10,7 +10,8 @@
 
 #pragma once
 
-#include <corsika/modules/null_model/NullModel.hpp>
+#include <corsika/modules/NullModel.hpp>
+
 #include <corsika/setup/SetupStack.hpp>
 #include <corsika/setup/SetupTrajectory.hpp>
 
@@ -18,7 +19,7 @@ namespace corsika::null_model {
 
   void NullModel::Init() {}
 
-  NullModel::NullModel(corsika::units::si::LengthType maxStepLength)
+  NullModel::NullModel(LengthType maxStepLength)
       : fMaxStepLength(maxStepLength) {}
 
   template <>
@@ -28,8 +29,8 @@ namespace corsika::null_model {
   }
 
   template <>
-  units::si::LengthType NullModel::MaxStepLength(corsika::setup::Stack::ParticleType&,
-                                                 corsika::setup::Trajectory&) const {
+  LengthType NullModel::MaxStepLength(corsika::setup::Stack::ParticleType&,
+                                      corsika::setup::Trajectory&) const {
     return fMaxStepLength;
   }
 
diff --git a/corsika/detail/modules/ObservationPlane.inl b/corsika/detail/modules/ObservationPlane.inl
new file mode 100644
index 0000000000000000000000000000000000000000..f588eb5f63164d6064c93f6bf44ffbbd94f033f5
--- /dev/null
+++ b/corsika/detail/modules/ObservationPlane.inl
@@ -0,0 +1,66 @@
+/*
+ * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <corsika/modules/ObservationPlane.hpp>
+
+#include <fstream>
+
+namespace corsika::observation_plane {
+
+  ObservationPlane::ObservationPlane(corsika::Plane const& obsPlane,
+                                     std::string const& filename, bool deleteOnHit)
+      : plane_(obsPlane)
+      , outputStream_(filename)
+      , deleteOnHit_(deleteOnHit) {
+    outputStream_ << "#PDG code, energy / eV, distance to center / m" << std::endl;
+  }
+
+  corsika::EProcessReturn ObservationPlane::DoContinuous(
+      corsika::setup::Stack::ParticleType const& particle,
+      corsika::setup::Trajectory const& trajectory) {
+    TimeType const timeOfIntersection =
+        (plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) /
+        trajectory.GetV0().dot(plane_.GetNormal());
+
+    if (timeOfIntersection < TimeType::zero()) { return corsika::EProcessReturn::eOk; }
+
+    if (plane_.IsAbove(trajectory.GetR0()) == plane_.IsAbove(trajectory.GetPosition(1))) {
+      return corsika::EProcessReturn::eOk;
+    }
+
+    outputStream_ << static_cast<int>(corsika::GetPDG(particle.GetPID())) << ' '
+                  << particle.GetEnergy() * (1 / 1_eV) << ' '
+                  << (trajectory.GetPosition(1) - plane_.GetCenter()).norm() / 1_m
+                  << std::endl;
+
+    if (deleteOnHit_) {
+      return corsika::EProcessReturn::eParticleAbsorbed;
+    } else {
+      return corsika::EProcessReturn::eOk;
+    }
+  }
+
+  corsika::LengthType ObservationPlane::MaxStepLength(
+      corsika::setup::Stack::ParticleType const&,
+      corsika::setup::Trajectory const& trajectory) {
+
+    TimeType const timeOfIntersection =
+        (plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) /
+        trajectory.GetV0().dot(plane_.GetNormal());
+
+    if (timeOfIntersection < TimeType::zero()) {
+      return std::numeric_limits<double>::infinity() * 1_m;
+    }
+
+    auto const pointOfIntersection = trajectory.GetPosition(timeOfIntersection);
+    return (trajectory.GetR0() - pointOfIntersection).norm() * 1.0001;
+  }
+
+} // namespace corsika::observation_plane
\ No newline at end of file
diff --git a/corsika/detail/modules/ParticleCut.inl b/corsika/detail/modules/ParticleCut.inl
new file mode 100644
index 0000000000000000000000000000000000000000..53a3f2b764513e468c515eb1b076838c448371c0
--- /dev/null
+++ b/corsika/detail/modules/ParticleCut.inl
@@ -0,0 +1,109 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/modules/ParticleCut.hpp>
+
+namespace corsika::particle_cut {
+
+  template <typename TParticle>
+  bool ParticleCut::ParticleIsBelowEnergyCut(TParticle const& vP) const {
+    auto const energyLab = vP.GetEnergy();
+    // nuclei
+    if (vP.GetPID() == corsika::Code::Nucleus) {
+      // calculate energy per nucleon
+      auto const ElabNuc = energyLab / vP.GetNuclearA();
+      return (ElabNuc < fECut);
+    } else {
+      return (energyLab < fECut);
+    }
+  }
+
+  bool ParticleCut::ParticleIsEmParticle(Code vCode) const {
+    // FOR NOW: switch
+    switch (vCode) {
+      case Code::Gamma:
+      case Code::Electron:
+      case Code::Positron:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  bool ParticleCut::ParticleIsInvisible(Code vCode) const {
+    switch (vCode) {
+      case Code::NuE:
+      case Code::NuEBar:
+      case Code::NuMu:
+      case Code::NuMuBar:
+        return true;
+
+      default:
+        return false;
+    }
+  }
+
+  EProcessReturn ParticleCut::DoSecondaries(corsika::setup::StackView& vS) {
+
+    auto p = vS.begin();
+    while (p != vS.end()) {
+      const Code pid = p.GetPID();
+      HEPEnergyType energy = p.GetEnergy();
+      std::cout << "ProcessCut: DoSecondaries: " << pid << " E= " << energy
+                << ", EcutTot=" << (fEmEnergy + fInvEnergy + fEnergy) / 1_GeV << " GeV"
+                << std::endl;
+      if (ParticleIsEmParticle(pid)) {
+        std::cout << "removing em. particle..." << std::endl;
+        fEmEnergy += energy;
+        fEmCount += 1;
+        p.Delete();
+      } else if (ParticleIsInvisible(pid)) {
+        std::cout << "removing inv. particle..." << std::endl;
+        fInvEnergy += energy;
+        fInvCount += 1;
+        p.Delete();
+      } else if (ParticleIsBelowEnergyCut(p)) {
+        std::cout << "removing low en. particle..." << std::endl;
+        fEnergy += energy;
+        p.Delete();
+      } else if (p.GetTime() > 10_ms) {
+        std::cout << "removing OLD particle..." << std::endl;
+        fEnergy += energy;
+        p.Delete();
+      } else {
+        ++p; // next entry in SecondaryView
+      }
+    }
+    return EProcessReturn::eOk;
+  }
+
+  void ParticleCut::Init() {
+    fEmEnergy = 0_GeV;
+    fEmCount = 0;
+    fInvEnergy = 0_GeV;
+    fInvCount = 0;
+    fEnergy = 0_GeV;
+    // defineEmParticles();
+  }
+
+  void ParticleCut::ShowResults() {
+    std::cout << " ******************************" << std::endl
+              << " ParticleCut: " << std::endl
+              << " energy in em.  component (GeV):  " << fEmEnergy / 1_GeV << std::endl
+              << " no. of em.  particles injected:  " << fEmCount << std::endl
+              << " energy in inv. component (GeV):  " << fInvEnergy / 1_GeV << std::endl
+              << " no. of inv. particles injected:  " << fInvCount << std::endl
+              << " energy below particle cut (GeV): " << fEnergy / 1_GeV << std::endl
+              << " ******************************" << std::endl;
+  }
+
+} // namespace corsika::particle_cut
diff --git a/corsika/detail/modules/stack_inspector/StackInspector.inl b/corsika/detail/modules/StackInspector.inl
similarity index 92%
rename from corsika/detail/modules/stack_inspector/StackInspector.inl
rename to corsika/detail/modules/StackInspector.inl
index 3a49d683d9ae9945e3c2cbbe016e040453dce692..a6edb39a5c0c230b17292f4f08d172d696a02723 100644
--- a/corsika/detail/modules/stack_inspector/StackInspector.inl
+++ b/corsika/detail/modules/StackInspector.inl
@@ -10,10 +10,11 @@
 
 #pragma once
 
+#include <corsika/modules/StackInspector.hpp>
+
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/RootCoordinateSystem.hpp>
-#include <corsika/modules/stack_inspector/StackInspector.hpp>
 
 #include <corsika/setup/SetupTrajectory.hpp>
 
@@ -26,7 +27,7 @@ namespace corsika::stack_inspector {
 
   template <typename TStack>
   StackInspector<TStack>::StackInspector(const int vNStep, const bool vReportStack,
-                                         const corsika::units::si::HEPEnergyType vE0)
+                                         const HEPEnergyType vE0)
       : StackProcess<StackInspector<TStack>>(vNStep)
       , ReportStack_(vReportStack)
       , E0_(vE0)
@@ -38,13 +39,11 @@ namespace corsika::stack_inspector {
   template <typename TStack>
   corsika::EProcessReturn StackInspector<TStack>::DoStack(const TStack& vS) {
 
-    using namespace units::si;
-
     [[maybe_unused]] int i = 0;
     HEPEnergyType Etot = 0_GeV;
 
     for (const auto& iterP : vS) {
-      units::si::HEPEnergyType E = iterP.GetEnergy();
+      HEPEnergyType E = iterP.GetEnergy();
       Etot += E;
       if (ReportStack_) {
         corsika::CoordinateSystem& rootCS =
@@ -79,7 +78,7 @@ namespace corsika::stack_inspector {
               << ", nStep=" << GetStep() << ", stackSize=" << vS.GetSize()
               << ", Estack=" << Etot / 1_GeV << " GeV"
               << ", ETA=" << std::put_time(std::localtime(&eta_time), "%T") << std::endl;
-              
+
     return corsika::EProcessReturn::eOk;
   }
 
diff --git a/corsika/detail/modules/track_writer/TrackWriter.inl b/corsika/detail/modules/TrackWriter.inl
similarity index 89%
rename from corsika/detail/modules/track_writer/TrackWriter.inl
rename to corsika/detail/modules/TrackWriter.inl
index 82e3688388e5b440a12cbbd0e65428d371161aad..8a6f1e5c242644691d1cc9b7f481e28aa8811056 100644
--- a/corsika/detail/modules/track_writer/TrackWriter.inl
+++ b/corsika/detail/modules/TrackWriter.inl
@@ -10,7 +10,7 @@
 
 #pragma once
 
-#include <corsika/modules/track_writer/TrackWriter.hpp>
+#include <corsika/modules/TrackWriter.hpp>
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 
@@ -33,7 +33,6 @@ namespace corsika::track_writer {
   template <typename TParticle, typename TTrack>
   corsika::EProcessReturn TrackWriter::DoContinuous(const TParticle& vP,
                                                     const TTrack& vT) {
-    using namespace units::si;
     auto const start = vT.GetPosition(0).GetCoordinates();
     auto const delta = vT.GetPosition(1).GetCoordinates() - start;
     auto const pdg = static_cast<int>(corsika::GetPDG(vP.GetPID()));
@@ -53,8 +52,8 @@ namespace corsika::track_writer {
   }
 
   template <typename TParticle, typename TTrack>
-  units::si::LengthType TrackWriter::MaxStepLength(const TParticle&, const TTrack&) {
-    return units::si::meter * std::numeric_limits<double>::infinity();
+  LengthType TrackWriter::MaxStepLength(const TParticle&, const TTrack&) {
+    return meter * std::numeric_limits<double>::infinity();
   }
 
 } // namespace corsika::track_writer
diff --git a/corsika/detail/modules/tracking_line/TrackingLine.inl b/corsika/detail/modules/TrackingLine.inl
similarity index 82%
rename from corsika/detail/modules/tracking_line/TrackingLine.inl
rename to corsika/detail/modules/TrackingLine.inl
index fa9d86db8fb574491cc99433a6bb5215258355c6..d75d93e794b30437c812f69267f3fc911de36619 100644
--- a/corsika/detail/modules/tracking_line/TrackingLine.inl
+++ b/corsika/detail/modules/TrackingLine.inl
@@ -10,7 +10,7 @@
 
 #pragma once
 
-#include <corsika/modules/tracking_line/TrackingLine.hpp>
+#include <corsika/modules/TrackingLine.hpp>
 
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/QuantityVector.hpp>
@@ -24,7 +24,7 @@
 
 namespace corsika::tracking_line {
 
-  std::optional<std::pair<units::si::TimeType, units::si::TimeType>> TimeOfIntersection(
+  std::optional<std::pair<TimeType, TimeType>> TimeOfIntersection(
       corsika::Line const& line, corsika::Sphere const& sphere) {
     auto const delta = line.GetR0() - sphere.GetCenter();
     auto const v = line.GetV0();
@@ -46,9 +46,7 @@ namespace corsika::tracking_line {
     }
   }
 
-  units::si::TimeType TimeOfIntersection(Line const& vLine, Plane const& vPlane) {
-
-    using namespace units::si;
+  TimeType TimeOfIntersection(Line const& vLine, Plane const& vPlane) {
 
     auto const delta = vPlane.GetCenter() - vLine.GetR0();
     auto const v = vLine.GetV0();
@@ -56,10 +54,10 @@ namespace corsika::tracking_line {
     auto const c = n.dot(v);
 
     if (c.magnitude() == 0) {
-      return std::numeric_limits<units::si::TimeType::value_type>::infinity() * 1_s;
+      return std::numeric_limits<TimeType::value_type>::infinity() * 1_s;
     } else {
       return n.dot(delta) / c;
     }
   }
-  
+
 } // namespace corsika::tracking_line
diff --git a/corsika/detail/modules/energy_loss/EnergyLoss.inl b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl
similarity index 79%
rename from corsika/detail/modules/energy_loss/EnergyLoss.inl
rename to corsika/detail/modules/energy_loss/BetheBlochPDG.inl
index c4e883086e104bd88ef7373edf3fbcfc9387503c..73ac0566129cc30be971aca344975146dc6fdfbb 100644
--- a/corsika/detail/modules/energy_loss/EnergyLoss.inl
+++ b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl
@@ -10,7 +10,7 @@
 
 #pragma once
 
-#include <corsika/modules/energy_loss/EnergyLoss.hpp>
+#include <corsika/modules/energy_loss/BetheBlochPDG.hpp>
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 
@@ -29,8 +29,7 @@ using SetupTrack = corsika::setup::Trajectory;
 
 namespace corsika::energy_loss {
 
-  auto elab2plab = [](corsika::units::si::HEPEnergyType Elab,
-                      corsika::units::si::HEPMassType m) {
+  auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) {
     return sqrt((Elab - m) * (Elab + m));
   };
 
@@ -48,10 +47,7 @@ namespace corsika::energy_loss {
    * For shell correction, see Sec 6 of https://www.nap.edu/read/20066/chapter/8#115
    *
    */
-  corsika::units::si::HEPEnergyType EnergyLoss::BetheBloch(
-      SetupParticle const& p, corsika::units::si::GrammageType const dX) {
-
-    using namespace corsika::units::si;
+  HEPEnergyType BetheBlochPDG::BetheBloch(SetupParticle const& p, GrammageType const dX) {
 
     // all these are material constants and have to come through Environment
     // right now: values for nitrogen_D
@@ -93,8 +89,8 @@ namespace corsika::energy_loss {
     // Sternheimer parameterization, density corrections towards high energies
     // NOTE/TODO: when Cbar is 0 it needs to be approximated from parameterization ->
     // MISSING
-    std::cout << "BetheBloch p.GetMomentum().GetNorm()/m=" << p.GetMomentum().GetNorm() / m
-         << std::endl;
+    std::cout << "BetheBloch p.GetMomentum().GetNorm()/m="
+              << p.GetMomentum().GetNorm() / m << std::endl;
     double const x = log10(p.GetMomentum().GetNorm() / m);
     double delta = 0;
     if (x >= x1) {
@@ -138,8 +134,8 @@ namespace corsika::energy_loss {
     double const y2 = Z * Z * alpha * alpha / beta2;
     double const bloch = -y2 * (1.202 - y2 * (1.042 - 0.855 * y2 + 0.343 * y2 * y2));
 
-    // std::cout << "BetheBloch Erel=" << Erel << " barkas=" << barkas << " bloch=" << bloch <<
-    // std::endl;
+    // std::cout << "BetheBloch Erel=" << Erel << " barkas=" << barkas << " bloch=" <<
+    // bloch << std::endl;
 
     double const aux = 2 * me * c2 * beta2 * gamma2 * Wmax / (Ieff * Ieff);
     return -K * Z2 * ZoverA / beta2 *
@@ -147,36 +143,34 @@ namespace corsika::energy_loss {
   }
 
   // radiation losses according to PDG 2018, ch. 33 ref. [5]
-  corsika::units::si::HEPEnergyType EnergyLoss::RadiationLosses(SetupParticle const& vP,
-                                                                corsika::units::si::GrammageType const vDX) {
-    using namespace corsika::units::si;
+  HEPEnergyType BetheBlochPDG::RadiationLosses(SetupParticle const& vP,
+                                               GrammageType const vDX) {
     // simple-minded hard-coded value for b(E) inspired by data from
     // http://pdg.lbl.gov/2018/AtomicNuclearProperties/ for N and O.
     auto constexpr b = 3.0 * 1e-6 * square(1_cm) / 1_g;
     return -vP.GetEnergy() * b * vDX;
   }
 
-  corsika::units::si::HEPEnergyType EnergyLoss::TotalEnergyLoss(SetupParticle const& vP,
-                                                                corsika::units::si::GrammageType const vDX) {
+  HEPEnergyType BetheBlochPDG::TotalEnergyLoss(SetupParticle const& vP,
+                                               GrammageType const vDX) {
     return BetheBloch(vP, vDX) + RadiationLosses(vP, vDX);
   }
 
-  corsika::EProcessReturn EnergyLoss::DoContinuous(SetupParticle& p,
-                                                   SetupTrack const& t) {
-    using namespace corsika::units::si;
+  corsika::EProcessReturn BetheBlochPDG::DoContinuous(SetupParticle& p,
+                                                      SetupTrack const& t) {
     if (p.GetChargeNumber() == 0) return corsika::EProcessReturn::eOk;
 
     GrammageType const dX =
         p.GetNode()->GetModelProperties().IntegratedGrammage(t, t.GetLength());
-    std::cout << "EnergyLoss " << p.GetPID() << ", z=" << p.GetChargeNumber()
-         << ", dX=" << dX / 1_g * square(1_cm) << "g/cm2" << std::endl;
+    std::cout << "BetheBlochPDG " << p.GetPID() << ", z=" << p.GetChargeNumber()
+              << ", dX=" << dX / 1_g * square(1_cm) << "g/cm2" << std::endl;
     HEPEnergyType dE = TotalEnergyLoss(p, dX);
     auto E = p.GetEnergy();
     const auto Ekin = E - p.GetMass();
     auto Enew = E + dE;
-    std::cout << "EnergyLoss  dE=" << dE / 1_MeV << "MeV, "
-         << " E=" << E / 1_GeV << "GeV,  Ekin=" << Ekin / 1_GeV
-         << ", Enew=" << Enew / 1_GeV << "GeV" << std::endl;
+    std::cout << "BetheBlochPDG  dE=" << dE / 1_MeV << "MeV, "
+              << " E=" << E / 1_GeV << "GeV,  Ekin=" << Ekin / 1_GeV
+              << ", Enew=" << Enew / 1_GeV << "GeV" << std::endl;
     auto status = corsika::EProcessReturn::eOk;
     if (-dE > Ekin) {
       dE = -Ekin;
@@ -185,16 +179,15 @@ namespace corsika::energy_loss {
     }
     p.SetEnergy(Enew);
     MomentumUpdate(p, Enew);
-    EnergyLossTot_ += dE;
+    BetheBlochPDGTot_ += dE;
     FillProfile(p, t, dE);
     return status;
   }
 
-  corsika::units::si::LengthType EnergyLoss::MaxStepLength(
-      SetupParticle const& vParticle, SetupTrack const& vTrack) const {
-    using namespace corsika::units::si;
+  LengthType BetheBlochPDG::MaxStepLength(SetupParticle const& vParticle,
+                                          SetupTrack const& vTrack) const {
     if (vParticle.GetChargeNumber() == 0) {
-      return units::si::meter * std::numeric_limits<double>::infinity();
+      return meter * std::numeric_limits<double>::infinity();
     }
 
     auto constexpr dX = 1_g / square(1_cm);
@@ -208,18 +201,15 @@ namespace corsika::energy_loss {
            1.0001; // to make sure particle gets absorbed when DoContinuous() is called
   }
 
-  void EnergyLoss::MomentumUpdate(corsika::setup::Stack::ParticleType& vP,
-                                  corsika::units::si::HEPEnergyType Enew) {
-    using namespace corsika::units::si;
+  void BetheBlochPDG::MomentumUpdate(corsika::setup::Stack::ParticleType& vP,
+                                     HEPEnergyType Enew) {
     HEPMomentumType Pnew = elab2plab(Enew, vP.GetMass());
     auto pnew = vP.GetMomentum();
     vP.SetMomentum(pnew * Pnew / pnew.GetNorm());
   }
 
-  void EnergyLoss::FillProfile(SetupParticle const& vP, SetupTrack const& vTrack,
-                               const corsika::units::si::HEPEnergyType dE) {
-
-    using namespace corsika::units::si;
+  void BetheBlochPDG::FillProfile(SetupParticle const& vP, SetupTrack const& vTrack,
+                                  const HEPEnergyType dE) {
 
     auto const toStart = vTrack.GetPosition(0) - InjectionPoint_;
     auto const toEnd = vTrack.GetPosition(1) - InjectionPoint_;
@@ -270,10 +260,10 @@ namespace corsika::energy_loss {
     std::cout << "total energy added to histogram: " << energyCount << std::endl;
   }
 
-  void EnergyLoss::PrintProfile() const {
-    using namespace corsika::units::si;
-    std::ofstream file("EnergyLossProfile.dat");
-    std::cout << "# EnergyLoss PrintProfile  X-bin [g/cm2]  dE/dX [GeV/g/cm2]  " << std::endl;
+  void BetheBlochPDG::PrintProfile() const {
+    std::ofstream file("BetheBlochPDGProfile.dat");
+    std::cout << "# BetheBlochPDG PrintProfile  X-bin [g/cm2]  dE/dX [GeV/g/cm2]  "
+              << std::endl;
     double const deltaX = dX_ / 1_g * square(1_cm);
     for (auto v : Profile_) {
       file << v.first * deltaX << " " << v.second / (deltaX * 1_GeV) << std::endl;
diff --git a/corsika/detail/modules/observation_plane/ObservationPlane.inl b/corsika/detail/modules/observation_plane/ObservationPlane.inl
deleted file mode 100644
index 87a7a0410fa70edd6bf68761d49550a20c2eae1b..0000000000000000000000000000000000000000
--- a/corsika/detail/modules/observation_plane/ObservationPlane.inl
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
- *
- * This software is distributed under the terms of the GNU General Public
- * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
- * the license.
- */
-
-#include <corsika/modules/observation_plane/ObservationPlane.hpp>
-
-#include <fstream>
-
-namespace corsika::observation_plane {
-
-ObservationPlane::ObservationPlane(corsika::Plane const& obsPlane,
-                                   std::string const& filename, bool deleteOnHit)
-    : plane_(obsPlane)
-    , outputStream_(filename)
-    , deleteOnHit_(deleteOnHit) {
-  outputStream_ << "#PDG code, energy / eV, distance to center / m" << std::endl;
-}
-
-corsika::EProcessReturn ObservationPlane::DoContinuous(
-                                 corsika::setup::Stack::ParticleType const& particle, corsika::setup::Trajectory const& trajectory) {
-  using namespace corsika::units::si;
-
-  TimeType const timeOfIntersection =
-      (plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) /
-      trajectory.GetV0().dot(plane_.GetNormal());
-
-  if (timeOfIntersection < TimeType::zero()) { return corsika::EProcessReturn::eOk; }
-
-  if (plane_.IsAbove(trajectory.GetR0()) == plane_.IsAbove(trajectory.GetPosition(1))) {
-    return corsika::EProcessReturn::eOk;
-  }
-
-  outputStream_ << static_cast<int>(corsika::GetPDG(particle.GetPID())) << ' '
-                << particle.GetEnergy() * (1 / 1_eV) << ' '
-                << (trajectory.GetPosition(1) - plane_.GetCenter()).norm() / 1_m
-                << std::endl;
-
-  if (deleteOnHit_) {
-    return corsika::EProcessReturn::eParticleAbsorbed;
-  } else {
-    return corsika::EProcessReturn::eOk;
-  }
-}
-
-corsika::LengthType ObservationPlane::MaxStepLength(corsika::setup::Stack::ParticleType const&,
-                                           corsika::setup::Trajectory const& trajectory) {
-
-  using namespace corsika::units::si;
-
-TimeType const timeOfIntersection =
-      (plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) /
-      trajectory.GetV0().dot(plane_.GetNormal());
-
-  if (timeOfIntersection < TimeType::zero()) {
-    return std::numeric_limits<double>::infinity() * 1_m;
-  }
-
-  auto const pointOfIntersection = trajectory.GetPosition(timeOfIntersection);
-  return (trajectory.GetR0() - pointOfIntersection).norm() * 1.0001;
-}
-
-}
\ No newline at end of file
diff --git a/corsika/detail/modules/particle_cut/ParticleCut.inl b/corsika/detail/modules/particle_cut/ParticleCut.inl
deleted file mode 100644
index bd739a5f581fd7a96b2353189edc67be53c9b6ca..0000000000000000000000000000000000000000
--- a/corsika/detail/modules/particle_cut/ParticleCut.inl
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
- *
- * This software is distributed under the terms of the GNU General Public
- * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
- * the license.
- */
-
-#pragma once
-
-#include <corsika/modules/particle_cut/ParticleCut.hpp>
-
-namespace corsika::particle_cut {
-
-    template <typename TParticle>
-    bool ParticleCut::ParticleIsBelowEnergyCut(TParticle const& vP) const {
-      auto const energyLab = vP.GetEnergy();
-      // nuclei
-      if (vP.GetPID() == corsika::Code::Nucleus) {
-        // calculate energy per nucleon
-        auto const ElabNuc = energyLab / vP.GetNuclearA();
-        return (ElabNuc < fECut);
-      } else {
-        return (energyLab < fECut);
-      }
-    }
-
-    bool ParticleCut::ParticleIsEmParticle(Code vCode) const {
-      // FOR NOW: switch
-      switch (vCode) {
-        case Code::Gamma:
-        case Code::Electron:
-        case Code::Positron:
-          return true;
-        default:
-          return false;
-      }
-    }
-
-    bool ParticleCut::ParticleIsInvisible(Code vCode) const {
-      switch (vCode) {
-        case Code::NuE:
-        case Code::NuEBar:
-        case Code::NuMu:
-        case Code::NuMuBar:
-          return true;
-
-        default:
-          return false;
-      }
-    }
-
-    EProcessReturn ParticleCut::DoSecondaries(corsika::setup::StackView& vS) {
-
-    using namespace units::si;
-
-      auto p = vS.begin();
-      while (p != vS.end()) {
-        const Code pid = p.GetPID();
-        units::si::HEPEnergyType energy = p.GetEnergy();
-        std::cout << "ProcessCut: DoSecondaries: " << pid << " E= " << energy
-             << ", EcutTot=" << (fEmEnergy + fInvEnergy + fEnergy) / 1_GeV << " GeV"
-             << std::endl;
-        if (ParticleIsEmParticle(pid)) {
-          std::cout << "removing em. particle..." << std::endl;
-          fEmEnergy += energy;
-          fEmCount += 1;
-          p.Delete();
-        } else if (ParticleIsInvisible(pid)) {
-          std::cout << "removing inv. particle..." << std::endl;
-          fInvEnergy += energy;
-          fInvCount += 1;
-          p.Delete();
-        } else if (ParticleIsBelowEnergyCut(p)) {
-          std::cout << "removing low en. particle..." << std::endl;
-          fEnergy += energy;
-          p.Delete();
-        } else if (p.GetTime() > 10_ms) {
-          std::cout << "removing OLD particle..." << std::endl;
-          fEnergy += energy;
-          p.Delete();
-        } else {
-          ++p; // next entry in SecondaryView
-        }
-      }
-      return EProcessReturn::eOk;
-    }
-
-    void ParticleCut::Init() {
-      using namespace units::si;
-      fEmEnergy = 0_GeV;
-      fEmCount = 0;
-      fInvEnergy = 0_GeV;
-      fInvCount = 0;
-      fEnergy = 0_GeV;
-      // defineEmParticles();
-    }
-
-    void ParticleCut::ShowResults() {
-      using namespace units::si;
-      std::cout << " ******************************" << std::endl
-           << " ParticleCut: " << std::endl
-           << " energy in em.  component (GeV):  " << fEmEnergy / 1_GeV << std::endl
-           << " no. of em.  particles injected:  " << fEmCount << std::endl
-           << " energy in inv. component (GeV):  " << fInvEnergy / 1_GeV << std::endl
-           << " no. of inv. particles injected:  " << fInvCount << std::endl
-           << " energy below particle cut (GeV): " << fEnergy / 1_GeV << std::endl
-           << " ******************************" << std::endl;
-    }
-    
-} // namespace corsika::particle_cut
diff --git a/corsika/detail/modules/pythia8/Decay.inl b/corsika/detail/modules/pythia8/Decay.inl
index b407bee40862ac4dffecdbeaaf8e05392305e223..c0e4d7e0cac7bb1e8585a742eb54aef02b3d5873 100644
--- a/corsika/detail/modules/pythia8/Decay.inl
+++ b/corsika/detail/modules/pythia8/Decay.inl
@@ -59,8 +59,7 @@ namespace corsika::pythia8 {
   }
 
   template <typename TParticle>
-  units::si::TimeType Decay::GetLifetime(TParticle const& p) {
-    using namespace units::si;
+  TimeType Decay::GetLifetime(TParticle const& p) {
 
     HEPEnergyType E = p.GetEnergy();
     HEPMassType m = p.GetMass();
@@ -76,7 +75,6 @@ namespace corsika::pythia8 {
   template <typename TProjectile>
   void Decay::DoDecay(TProjectile& vP) {
     using corsika::Point;
-    using namespace units::si;
 
     auto const decayPoint = vP.GetPosition();
     auto const t0 = vP.GetTime();
@@ -124,17 +122,17 @@ namespace corsika::pythia8 {
         MomentumVector pyP(rootCS, {event[i].px() * 1_GeV, event[i].py() * 1_GeV,
                                     event[i].pz() * 1_GeV});
 
-        std::cout << "particle: id=" << pyId << " momentum=" << pyP.GetComponents() / 1_GeV
-             << " energy=" << pyEn << std::endl;
+        std::cout << "particle: id=" << pyId
+                  << " momentum=" << pyP.GetComponents() / 1_GeV << " energy=" << pyEn
+                  << std::endl;
 
         vP.AddSecondary(
-            std::tuple<corsika::Code, units::si::HEPEnergyType,
-                  corsika::MomentumVector, corsika::Point, units::si::TimeType>{
-                pyId, pyEn, pyP, decayPoint, t0});
+            std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector,
+                       corsika::Point, TimeType>{pyId, pyEn, pyP, decayPoint, t0});
       }
 
     // set particle stable
     Decay::SetStable(vP.GetPID());
   }
 
-} // namespace corsika::process::pythia
+} // namespace corsika::pythia8
diff --git a/corsika/detail/modules/pythia8/Interaction.inl b/corsika/detail/modules/pythia8/Interaction.inl
index 33b649912723afe43e35b9f5698d93fc836ef27a..649ea2ad7d4734506f521f8f708f22677c5e1551 100644
--- a/corsika/detail/modules/pythia8/Interaction.inl
+++ b/corsika/detail/modules/pythia8/Interaction.inl
@@ -25,7 +25,7 @@ using Particle = corsika::setup::Stack::ParticleType;
 
 namespace corsika::pythia8 {
 
-  typedef corsika::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
+  typedef corsika::Vector<corsika::hepmomentum_d> MomentumVector;
 
   Interaction::~Interaction() {
     std::cout << "Pythia::Interaction n=" << fCount << std::endl;
@@ -85,10 +85,9 @@ namespace corsika::pythia8 {
     fPythia.particleData.mayDecay(static_cast<int>(corsika::GetPDG(pCode)), false);
   }
 
-  void Interaction::ConfigureLabFrameCollision(
-      const corsika::Code BeamId, const corsika::Code TargetId,
-      const units::si::HEPEnergyType BeamEnergy) {
-    using namespace units::si;
+  void Interaction::ConfigureLabFrameCollision(const corsika::Code BeamId,
+                                               const corsika::Code TargetId,
+                                               const HEPEnergyType BeamEnergy) {
     // Pythia configuration of the current event
     // very clumsy. I am sure this can be done better..
 
@@ -125,11 +124,9 @@ namespace corsika::pythia8 {
            pCode == corsika::Code::PiMinus || pCode == corsika::Code::PiPlus;
   }
 
-  std::tuple<units::si::CrossSectionType, units::si::CrossSectionType>
-  Interaction::GetCrossSection(const corsika::Code BeamId, const corsika::Code TargetId,
-                               const units::si::HEPEnergyType CoMenergy) {
-    using namespace units::si;
-
+  std::tuple<CrossSectionType, CrossSectionType> Interaction::GetCrossSection(
+      const corsika::Code BeamId, const corsika::Code TargetId,
+      const HEPEnergyType CoMenergy) {
     // interaction possible in pythia?
     if (TargetId == corsika::Code::Proton || TargetId == corsika::Code::Hydrogen) {
       if (CanInteract(BeamId) && ValidCoMEnergy(CoMenergy)) {
@@ -159,10 +156,7 @@ namespace corsika::pythia8 {
   }
 
   template <>
-  units::si::GrammageType Interaction::GetInteractionLength(Particle& p) {
-
-    using namespace units;
-    using namespace units::si;
+  GrammageType Interaction::GetInteractionLength(Particle& p) {
 
     // coordinate system, get global frame of reference
     CoordinateSystem& rootCS =
@@ -218,7 +212,7 @@ namespace corsika::pythia8 {
 
       // calculate interaction length in medium
       GrammageType const int_length = mediumComposition.GetAverageMassNumber() *
-                                      units::constants::u / weightedProdCrossSection;
+                                      constants::u / weightedProdCrossSection;
       std::cout << "Interaction: "
                 << "interaction length (g/cm2): " << int_length / (0.001_kg) * 1_cm * 1_cm
                 << std::endl;
@@ -237,9 +231,6 @@ namespace corsika::pythia8 {
   template <>
   corsika::EProcessReturn Interaction::DoInteraction(Projectile& vP) {
 
-    using namespace units;
-    using namespace units::si;
-
     const auto corsikaBeamId = vP.GetPID();
     std::cout << "Pythia::Interaction: "
               << "DoInteraction: " << corsikaBeamId << " interaction? "
@@ -376,9 +367,8 @@ namespace corsika::pythia8 {
 
           // add to corsika stack
           auto pnew = vP.AddSecondary(
-              std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                         corsika::Point, units::si::TimeType>{pyId, pyEn, pyPlab, pOrig,
-                                                              tOrig});
+              std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector,
+                         corsika::Point, TimeType>{pyId, pyEn, pyPlab, pOrig, tOrig});
 
           Plab_final += pnew.GetMomentum();
           Elab_final += pnew.GetEnergy();
diff --git a/corsika/detail/modules/qgsjetII/Interaction.inl b/corsika/detail/modules/qgsjetII/Interaction.inl
index 4ed30f2b0823fa7694e1ca71b1ba51ac4ccee70c..ec3ecb0676afa3b0a3757ad92f9eade7ee5ebb3c 100644
--- a/corsika/detail/modules/qgsjetII/Interaction.inl
+++ b/corsika/detail/modules/qgsjetII/Interaction.inl
@@ -17,7 +17,6 @@
 #include <corsika/modules/qgsjetII/ParticleConversion.hpp>
 #include <corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp>
 #include <corsika/modules/qgsjetII/QGSJetIIStack.hpp>
-#include <corsika/modules/qgsjetII/qgsjet-II-04.hpp>
 #include <corsika/setup/SetupStack.hpp>
 #include <corsika/setup/SetupTrajectory.hpp>
 #include <corsika/framework/utility/COMBoost.hpp>
@@ -26,6 +25,7 @@
 #include <string>
 #include <tuple>
 
+#include <qgsjet-II-04.hpp>
 
 namespace corsika::qgsjetII {
 
@@ -39,7 +39,9 @@ namespace corsika::qgsjetII {
     }
   }
 
-  Interaction::~Interaction() { std::cout << "QgsjetII::Interaction n=" << count_ << std::endl; }
+  Interaction::~Interaction() {
+    std::cout << "QgsjetII::Interaction n=" << count_ << std::endl;
+  }
 
   void Interaction::Init() {
 
@@ -54,11 +56,11 @@ namespace corsika::qgsjetII {
     }
   }
 
-  units::si::CrossSectionType Interaction::GetCrossSection(
-      const corsika::Code beamId, const corsika::Code targetId,
-      const units::si::HEPEnergyType Elab, const unsigned int Abeam,
-      const unsigned int targetA) const {
-    using namespace units::si;
+  CrossSectionType Interaction::GetCrossSection(const corsika::Code beamId,
+                                                const corsika::Code targetId,
+                                                const HEPEnergyType Elab,
+                                                const unsigned int Abeam,
+                                                const unsigned int targetA) const {
     double sigProd = std::numeric_limits<double>::infinity();
 
     if (corsika::qgsjetII::CanInteract(beamId)) {
@@ -81,7 +83,7 @@ namespace corsika::qgsjetII {
       }
 
       std::cout << "QgsjetII::GetCrossSection Elab=" << Elab << " iBeam=" << iBeam
-           << " iProjectile=" << iProjectile << " iTarget=" << iTarget << std::endl;
+                << " iProjectile=" << iProjectile << " iTarget=" << iTarget << std::endl;
       sigProd = qgsect_(Elab / 1_GeV, iBeam, iProjectile, iTarget);
       std::cout << "QgsjetII::GetCrossSection sigProd=" << sigProd << std::endl;
     }
@@ -90,10 +92,7 @@ namespace corsika::qgsjetII {
   }
 
   template <typename TParticle>
-  units::si::GrammageType Interaction::GetInteractionLength(
-  const TParticle& vP) const {
-
-    using namespace units::si;
+  GrammageType Interaction::GetInteractionLength(const TParticle& vP) const {
 
     // coordinate system, get global frame of reference
     CoordinateSystem& rootCS =
@@ -112,9 +111,9 @@ namespace corsika::qgsjetII {
     HEPEnergyType Elab = vP.GetEnergy();
 
     std::cout << "Interaction: LambdaInt: \n"
-         << " input energy: " << vP.GetEnergy() / 1_GeV << std::endl
-         << " beam can interact:" << kInteraction << std::endl
-         << " beam pid:" << vP.GetPID() << std::endl;
+              << " input energy: " << vP.GetEnergy() / 1_GeV << std::endl
+              << " beam can interact:" << kInteraction << std::endl
+              << " beam pid:" << vP.GetPID() << std::endl;
 
     if (kInteraction) {
 
@@ -132,24 +131,23 @@ namespace corsika::qgsjetII {
       const auto& mediumComposition =
           currentNode->GetModelProperties().GetNuclearComposition();
 
-      units::si::CrossSectionType weightedProdCrossSection = mediumComposition.WeightedSum(
-          [=](corsika::Code targetID) -> units::si::CrossSectionType {
+      CrossSectionType weightedProdCrossSection =
+          mediumComposition.WeightedSum([=](corsika::Code targetID) -> CrossSectionType {
             int targetA = 0;
-            if (corsika::IsNucleus(targetID))
-              targetA = corsika::GetNucleusA(targetID);
+            if (corsika::IsNucleus(targetID)) targetA = corsika::GetNucleusA(targetID);
             return GetCrossSection(corsikaBeamId, targetID, Elab, Abeam, targetA);
           });
 
       std::cout << "Interaction: "
-           << "IntLength: weighted CrossSection (mb): " << weightedProdCrossSection / 1_mb
-           << std::endl;
+                << "IntLength: weighted CrossSection (mb): "
+                << weightedProdCrossSection / 1_mb << std::endl;
 
       // calculate interaction length in medium
       GrammageType const int_length = mediumComposition.GetAverageMassNumber() *
-                                      units::constants::u / weightedProdCrossSection;
+                                      constants::u / weightedProdCrossSection;
       std::cout << "Interaction: "
-           << "interaction length (g/cm2): " << int_length / (0.001_kg) * 1_cm * 1_cm
-           << std::endl;
+                << "interaction length (g/cm2): " << int_length / (0.001_kg) * 1_cm * 1_cm
+                << std::endl;
 
       return int_length;
     }
@@ -165,12 +163,10 @@ namespace corsika::qgsjetII {
   template <typename TParticle>
   corsika::EProcessReturn Interaction::DoInteraction(TParticle& vP) {
 
-    using namespace units::si;
-
     const auto corsikaBeamId = vP.GetPID();
     std::cout << "ProcessQgsjetII: "
-         << "DoInteraction: " << corsikaBeamId << " interaction? "
-         << corsika::qgsjetII::CanInteract(corsikaBeamId) << std::endl;
+              << "DoInteraction: " << corsikaBeamId << " interaction? "
+              << corsika::qgsjetII::CanInteract(corsikaBeamId) << std::endl;
 
     if (corsika::qgsjetII::CanInteract(corsikaBeamId)) {
 
@@ -184,7 +180,7 @@ namespace corsika::qgsjetII {
       // define target
       // for QgsjetII is always a single nucleon
       // FOR NOW: target is always at rest
-      const auto targetEnergyLab = 0_GeV + units::constants::nucleonMass;
+      const auto targetEnergyLab = 0_GeV + constants::nucleonMass;
       const auto targetMomentumLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV);
       const FourVector PtargLab(targetEnergyLab, targetMomentumLab);
 
@@ -196,12 +192,14 @@ namespace corsika::qgsjetII {
       if (corsika::IsNucleus(corsikaBeamId)) beamA = vP.GetNuclearA();
 
       std::cout << "Interaction: ebeam lab: " << projectileEnergyLab / 1_GeV << std::endl
-           << "Interaction: pbeam lab: " << projectileMomentumLab.GetComponents() / 1_GeV
-           << std::endl;
+                << "Interaction: pbeam lab: "
+                << projectileMomentumLab.GetComponents() / 1_GeV << std::endl;
       std::cout << "Interaction: etarget lab: " << targetEnergyLab / 1_GeV << std::endl
-           << "Interaction: ptarget lab: " << targetMomentumLab.GetComponents() / 1_GeV << std::endl;
+                << "Interaction: ptarget lab: "
+                << targetMomentumLab.GetComponents() / 1_GeV << std::endl;
 
-      std::cout << "Interaction: position of interaction: " << pOrig.GetCoordinates() << std::endl;
+      std::cout << "Interaction: position of interaction: " << pOrig.GetCoordinates()
+                << std::endl;
       std::cout << "Interaction: time: " << tOrig << std::endl;
 
       // sample target mass number
@@ -214,13 +212,12 @@ namespace corsika::qgsjetII {
         should be passed from GetInteractionLength if possible
        */
       auto const& compVec = mediumComposition.GetComponents();
-      std::vector<units::si::CrossSectionType> cross_section_of_components(compVec.size());
+      std::vector<CrossSectionType> cross_section_of_components(compVec.size());
 
       for (size_t i = 0; i < compVec.size(); ++i) {
         auto const targetId = compVec[i];
         int targetA = 0;
-        if (corsika::IsNucleus(targetId))
-          targetA = corsika::GetNucleusA(targetId);
+        if (corsika::IsNucleus(targetId)) targetA = corsika::GetNucleusA(targetId);
         const auto sigProd =
             GetCrossSection(corsikaBeamId, targetId, projectileEnergyLab, beamA, targetA);
         cross_section_of_components[i] = sigProd;
@@ -241,7 +238,7 @@ namespace corsika::qgsjetII {
       int projQgsCode = 1;
       if (corsika::IsNucleus(corsikaBeamId)) projQgsCode = vP.GetNuclearA();
       std::cout << "Interaction: projectile qgsjetII code/A: " << projQgsCode << " "
-           << corsikaBeamId << std::endl;
+                << corsikaBeamId << std::endl;
       if (projQgsCode > maxMassNumber_ || projQgsCode < 1)
         throw std::runtime_error("QgsjetII target outside range.");
 
@@ -264,13 +261,13 @@ namespace corsika::qgsjetII {
       }
 
       std::cout << "Interaction: "
-           << " DoInteraction: E(GeV):" << projectileEnergyLab / 1_GeV << std::endl;
+                << " DoInteraction: E(GeV):" << projectileEnergyLab / 1_GeV << std::endl;
       count_++;
       qgini_(projectileEnergyLab / 1_GeV, kBeam, projQgsCode, targetQgsCode);
       // this is from CRMC, is this REALLY needed ???
       qgini_(projectileEnergyLab / 1_GeV, kBeam, projQgsCode, targetQgsCode);
       qgconf_();
-      
+
       // bookkeeping
       MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
       HEPEnergyType Elab_final = 0_GeV;
@@ -280,8 +277,8 @@ namespace corsika::qgsjetII {
       // CoM frame definition in QgsjetII projectile: +z
       auto const& originalCS = projectileMomentumLab.GetCoordinateSystem();
       corsika::CoordinateSystem const zAxisFrame =
-	originalCS.RotateToZ(projectileMomentumLab);
-      
+          originalCS.RotateToZ(projectileMomentumLab);
+
       // fragments
       QGSJetIIFragmentsStack qfs;
       for (auto& fragm : qfs) {
@@ -292,19 +289,22 @@ namespace corsika::qgsjetII {
           case 1: { // proton/neutron
             idFragm = corsika::Code::Proton;
 
-	    auto momentum = corsika::Vector(
-					     zAxisFrame,
-					     corsika::QuantityVector<hepmomentum_d>{0.0_GeV, 0.0_GeV,
-						 sqrt((projectileEnergyLab + corsika::Proton::GetMass()) *
-						      (projectileEnergyLab - corsika::Proton::GetMass()))});
-	    
-	    auto const energy = sqrt(momentum.squaredNorm() + square(corsika::GetMass(idFragm)));	    
-	    momentum.rebase(originalCS); // transform back into standard lab frame
-	    std::cout << "secondary fragment> id=" << idFragm << " p=" << momentum.GetComponents() << std::endl;
+            auto momentum = corsika::Vector(
+                zAxisFrame,
+                corsika::QuantityVector<hepmomentum_d>{
+                    0.0_GeV, 0.0_GeV,
+                    sqrt((projectileEnergyLab + corsika::Proton::GetMass()) *
+                         (projectileEnergyLab - corsika::Proton::GetMass()))});
+
+            auto const energy =
+                sqrt(momentum.squaredNorm() + square(corsika::GetMass(idFragm)));
+            momentum.rebase(originalCS); // transform back into standard lab frame
+            std::cout << "secondary fragment> id=" << idFragm
+                      << " p=" << momentum.GetComponents() << std::endl;
             auto pnew = vP.AddSecondary(
-                std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                      corsika::Point, units::si::TimeType>{
-		  idFragm, energy, momentum, pOrig, tOrig});
+                std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector,
+                           corsika::Point, TimeType>{idFragm, energy, momentum, pOrig,
+                                                     tOrig});
             Plab_final += pnew.GetMomentum();
             Elab_final += pnew.GetEnergy();
           } break;
@@ -324,21 +324,24 @@ namespace corsika::qgsjetII {
         }
 
         if (idFragm == corsika::Code::Nucleus) {
-	    auto momentum = corsika::Vector(
-					     zAxisFrame,
-					     corsika::QuantityVector<hepmomentum_d>{0.0_GeV, 0.0_GeV,
-						 sqrt((projectileEnergyLab + units::constants::nucleonMass * A) *
-						      (projectileEnergyLab - units::constants::nucleonMass * A))});
-	    
-	    auto const energy = sqrt(momentum.squaredNorm() + units::si::square(units::constants::nucleonMass*A));	    
-	    momentum.rebase(originalCS); // transform back into standard lab frame
-	    std::cout << "secondary fragment> id=" << idFragm << " p=" << momentum.GetComponents() << " A=" << A << " Z=" << Z << std::endl;
-            auto pnew = vP.AddSecondary(
-                std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-		corsika::Point, units::si::TimeType, unsigned short, unsigned short>{
-		  idFragm, energy, momentum, pOrig, tOrig, A, Z});
-            Plab_final += pnew.GetMomentum();
-            Elab_final += pnew.GetEnergy();
+          auto momentum = corsika::Vector(
+              zAxisFrame, corsika::QuantityVector<hepmomentum_d>{
+                              0.0_GeV, 0.0_GeV,
+                              sqrt((projectileEnergyLab + constants::nucleonMass * A) *
+                                   (projectileEnergyLab - constants::nucleonMass * A))});
+
+          auto const energy =
+              sqrt(momentum.squaredNorm() + square(constants::nucleonMass * A));
+          momentum.rebase(originalCS); // transform back into standard lab frame
+          std::cout << "secondary fragment> id=" << idFragm
+                    << " p=" << momentum.GetComponents() << " A=" << A << " Z=" << Z
+                    << std::endl;
+          auto pnew = vP.AddSecondary(
+              std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector,
+                         corsika::Point, TimeType, unsigned short, unsigned short>{
+                  idFragm, energy, momentum, pOrig, tOrig, A, Z});
+          Plab_final += pnew.GetMomentum();
+          Elab_final += pnew.GetEnergy();
         }
       }
 
@@ -349,23 +352,27 @@ namespace corsika::qgsjetII {
         auto momentum = psec.GetMomentum(zAxisFrame);
         auto const energy = psec.GetEnergy();
 
-	momentum.rebase(originalCS); // transform back into standard lab frame
-	std::cout << "secondary fragment> id=" << corsika::qgsjetII::ConvertFromQgsjetII(psec.GetPID()) << " p=" << momentum.GetComponents() << std::endl;
-	auto pnew = vP.AddSecondary(
-				    std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-				    corsika::Point, units::si::TimeType>{
-		  corsika::qgsjetII::ConvertFromQgsjetII(psec.GetPID()), energy, momentum, pOrig, tOrig});
-	Plab_final += pnew.GetMomentum();
-	Elab_final += pnew.GetEnergy();
+        momentum.rebase(originalCS); // transform back into standard lab frame
+        std::cout << "secondary fragment> id="
+                  << corsika::qgsjetII::ConvertFromQgsjetII(psec.GetPID())
+                  << " p=" << momentum.GetComponents() << std::endl;
+        auto pnew =
+            vP.AddSecondary(std::tuple<corsika::Code, HEPEnergyType,
+                                       corsika::MomentumVector, corsika::Point, TimeType>{
+                corsika::qgsjetII::ConvertFromQgsjetII(psec.GetPID()), energy, momentum,
+                pOrig, tOrig});
+        Plab_final += pnew.GetMomentum();
+        Elab_final += pnew.GetEnergy();
       }
-      std::cout << "conservation (all GeV): Ecm_final= n/a" /* << Ecm_final / 1_GeV*/ << std::endl
-           << "Elab_final=" << Elab_final / 1_GeV
-           << ", Plab_final=" << (Plab_final / 1_GeV).GetComponents()
-           << ", N_wounded,targ="
-           << QGSJetIIFragmentsStackData::GetWoundedNucleonsTarget()
-           << ", N_wounded,proj="
-           << QGSJetIIFragmentsStackData::GetWoundedNucleonsProjectile()
-           << ", N_fragm,proj=" << qfs.GetSize() << std::endl;
+      std::cout << "conservation (all GeV): Ecm_final= n/a" /* << Ecm_final / 1_GeV*/
+                << std::endl
+                << "Elab_final=" << Elab_final / 1_GeV
+                << ", Plab_final=" << (Plab_final / 1_GeV).GetComponents()
+                << ", N_wounded,targ="
+                << QGSJetIIFragmentsStackData::GetWoundedNucleonsTarget()
+                << ", N_wounded,proj="
+                << QGSJetIIFragmentsStackData::GetWoundedNucleonsProjectile()
+                << ", N_fragm,proj=" << qfs.GetSize() << std::endl;
     }
     return corsika::EProcessReturn::eOk;
   }
diff --git a/corsika/detail/modules/sibyll/Decay.inl b/corsika/detail/modules/sibyll/Decay.inl
index a6ffafa224d414759cd95c5a2aba6ef799edcbdf..e1e3978b29932ecbe2c42cae5d1513205e69d899 100644
--- a/corsika/detail/modules/sibyll/Decay.inl
+++ b/corsika/detail/modules/sibyll/Decay.inl
@@ -83,8 +83,7 @@ namespace corsika::sibyll {
   }
 
   template <>
-  units::si::TimeType Decay::GetLifetime(SetupParticle const& vP) const {
-    using namespace units::si;
+  TimeType Decay::GetLifetime(SetupParticle const& vP) const {
 
     HEPEnergyType E = vP.GetEnergy();
     HEPMassType m = vP.GetMass();
@@ -100,9 +99,9 @@ namespace corsika::sibyll {
     std::cout << "Decay: MinStep: t0: " << t0 << std::endl;
     std::cout << "Decay: MinStep: energy: " << E / 1_GeV << " GeV" << std::endl;
     std::cout << "Decay: momentum: " << vP.GetMomentum().GetComponents() / 1_GeV << " GeV"
-         << std::endl;
-    std::cout << "Decay: momentum: shell mass-kin. inv. mass " << mkin / 1_GeV / 1_GeV << " "
-         << m / 1_GeV * m / 1_GeV << std::endl;
+              << std::endl;
+    std::cout << "Decay: momentum: shell mass-kin. inv. mass " << mkin / 1_GeV / 1_GeV
+              << " " << m / 1_GeV * m / 1_GeV << std::endl;
     auto sib_id = corsika::sibyll::ConvertToSibyllRaw(vP.GetPID());
     std::cout << "Decay: sib mass: " << get_sibyll_mass2(sib_id) << std::endl;
     std::cout << "Decay: MinStep: gamma: " << gamma << std::endl;
@@ -114,7 +113,6 @@ namespace corsika::sibyll {
   template <>
   void Decay::DoDecay(SetupProjectile& vP) {
     using corsika::Point;
-    using namespace units::si;
 
     fCount++;
     SibStack ss;
@@ -146,15 +144,14 @@ namespace corsika::sibyll {
     sib_list_(print_unit);
 
     // copy particles from sibyll stack to corsika
-    for (auto& psib : ss) {
+    for (const auto& psib : ss) {
       // FOR NOW: skip particles that have decayed in Sibyll, move to iterator?
       if (psib.HasDecayed()) continue;
       // add to corsika stack
       vP.AddSecondary(
-      std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                Point, units::si::TimeType>{
-              corsika::sibyll::ConvertFromSibyll(psib.GetPID()), psib.GetEnergy(),
-              psib.GetMomentum(), decayPoint, t0});
+          std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector, Point,
+                     TimeType>{corsika::sibyll::ConvertFromSibyll(psib.GetPID()),
+                               psib.GetEnergy(), psib.GetMomentum(), decayPoint, t0});
     }
     // empty sibyll stack
     ss.Clear();
diff --git a/corsika/detail/modules/sibyll/Interaction.inl b/corsika/detail/modules/sibyll/Interaction.inl
index b27988241f1d2c2c907c69b30d8a92b03a190ffb..98a52ddca8e531870723d5ddece39bd3195f5efa 100644
--- a/corsika/detail/modules/sibyll/Interaction.inl
+++ b/corsika/detail/modules/sibyll/Interaction.inl
@@ -75,11 +75,10 @@ namespace corsika::sibyll {
     for (int i = 0; i < 99; ++i) s_csydec_.idb[i] = -1 * abs(s_csydec_.idb[i]);
   }
 
-  tuple<units::si::CrossSectionType, units::si::CrossSectionType>
+  tuple<corsika::CrossSectionType, corsika::CrossSectionType>
   Interaction::GetCrossSection(const corsika::Code BeamId,
                                const corsika::Code TargetId,
-                               const units::si::HEPEnergyType CoMenergy) const {
-    using namespace units::si;
+                               const corsika::HEPEnergyType CoMenergy) const {
     double sigProd, sigEla, dummy, dum1, dum3, dum4;
     double dumdif[3];
     const int iBeam = corsika::sibyll::GetSibyllXSCode(BeamId);
@@ -106,12 +105,9 @@ namespace corsika::sibyll {
 
 
   template <>
-  units::si::GrammageType Interaction::GetInteractionLength(
+  corsika::GrammageType Interaction::GetInteractionLength(
       SetupParticle const& vP) const {
 
-    using namespace units;
-    using namespace units::si;
-
     // coordinate system, get global frame of reference
     CoordinateSystem& rootCS =
         RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
@@ -166,7 +162,7 @@ namespace corsika::sibyll {
 
       // calculate interaction length in medium
       GrammageType const int_length = mediumComposition.GetAverageMassNumber() *
-                                      units::constants::u / weightedProdCrossSection;
+                                      constants::u / weightedProdCrossSection;
       std::cout << "Interaction: "
            << "interaction length (g/cm2): " << int_length / (0.001_kg) * 1_cm * 1_cm
            << std::endl;
@@ -182,10 +178,8 @@ namespace corsika::sibyll {
      event is copied (and boosted) into the shower lab frame.
    */
 
-  template <>
-  corsika::EProcessReturn Interaction::DoInteraction(SetupProjectile& vP) {
-
-    using namespace units::si;
+  template <typename TProjectile>
+  corsika::EProcessReturn Interaction::DoInteraction(TProjectile& vP) {
 
     const auto corsikaBeamId = vP.GetPID();
     std::cout << "ProcessSibyll: "
@@ -208,7 +202,7 @@ namespace corsika::sibyll {
       // define target
       // for Sibyll is always a single nucleon
       // FOR NOW: target is always at rest
-      const auto eTargetLab = 0_GeV + corsika::units::constants::nucleonMass;
+      const auto eTargetLab = 0_GeV + constants::nucleonMass;
       const auto pTargetLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV);
       const FourVector PtargLab(eTargetLab, pTargetLab);
 
@@ -227,7 +221,7 @@ namespace corsika::sibyll {
       // define target kinematics in lab frame
       // define boost to and from CoM frame
       // CoM frame definition in Sibyll projectile: +z
-      COMBoost const boost(PprojLab, corsika::units::constants::nucleonMass);
+      COMBoost const boost(PprojLab, constants::nucleonMass);
 
       // just for show:
       // boost projecticle
@@ -264,7 +258,7 @@ namespace corsika::sibyll {
        */
       //#warning reading interaction cross section again, should not be necessary
       auto const& compVec = mediumComposition.GetComponents();
-      std::vector<corsika::units::si::CrossSectionType> cross_section_of_components(compVec.size());
+      std::vector<si::CrossSectionType> cross_section_of_components(compVec.size());
 
       for (size_t i = 0; i < compVec.size(); ++i) {
         auto const targetId = compVec[i];
@@ -332,7 +326,7 @@ namespace corsika::sibyll {
 
         MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
         HEPEnergyType Elab_final = 0_GeV, Ecm_final = 0_GeV;
-        for (auto& psib : ss) {
+        for (const auto& psib : ss) {
 
           // skip corsika that have decayed in Sibyll
           if (psib.HasDecayed()) continue;
@@ -344,8 +338,8 @@ namespace corsika::sibyll {
 
           // add to corsika stack
           auto pnew = vP.AddSecondary(
-          std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                    corsika::Point, units::si::TimeType>{
+          std::tuple<corsika::Code, corsika::HEPEnergyType, corsika::MomentumVector,
+                    corsika::Point, corsika::TimeType>{
                   corsika::sibyll::ConvertFromSibyll(psib.GetPID()),
                   Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig,
                   tOrig});
diff --git a/corsika/detail/modules/sibyll/NuclearInteraction.inl b/corsika/detail/modules/sibyll/NuclearInteraction.inl
index 5f1c86225ab44fc98c050431e7720201539d361f..9bf72cf55b24dc5ae8a847543a2bb7b4dc303274 100644
--- a/corsika/detail/modules/sibyll/NuclearInteraction.inl
+++ b/corsika/detail/modules/sibyll/NuclearInteraction.inl
@@ -32,7 +32,8 @@ namespace corsika::sibyll {
 
   template <>
   NuclearInteraction<corsika::setup::SetupEnvironment>::~NuclearInteraction() {
-    std::cout << "Nuclib::NuclearInteraction n=" << count_ << " Nnuc=" << nucCount_ << std::endl;
+    std::cout << "Nuclib::NuclearInteraction n=" << count_ << " Nnuc=" << nucCount_
+              << std::endl;
   }
 
   template <>
@@ -51,16 +52,15 @@ namespace corsika::sibyll {
       for (auto& n : pNuclei) {
         auto const j = GetNucleusA(n);
         std::cout << " " << std::setprecision(5) << std::setw(8)
-             << cnucsignuc_.sigma[j - 1][k][i];
+                  << cnucsignuc_.sigma[j - 1][k][i];
       }
       std::cout << std::endl;
     }
   }
 
   template <>
-  void NuclearInteraction<corsika::setup::SetupEnvironment>::InitializeNuclearCrossSections() {
-
-    using namespace corsika::units::si;
+  void
+  NuclearInteraction<corsika::setup::SetupEnvironment>::InitializeNuclearCrossSections() {
 
     auto& universe = *(environment_.GetUniverse());
 
@@ -77,7 +77,8 @@ namespace corsika::sibyll {
       return allElementsInUniverse;
     });
 
-    std::cout << "NuclearInteraction: initializing nuclear cross sections..." << std::endl;
+    std::cout << "NuclearInteraction: initializing nuclear cross sections..."
+              << std::endl;
 
     // loop over target components, at most 4!!
     int k = -1;
@@ -86,8 +87,9 @@ namespace corsika::sibyll {
       std::cout << "NuclearInteraction: init target component: " << ptarg << std::endl;
       const int ib = GetNucleusA(ptarg);
       if (!hadronicInteraction_.IsValidTarget(ptarg)) {
-        std::cout << "NuclearInteraction::InitializeNuclearCrossSections: target nucleus? id="
-             << ptarg << std::endl;
+        std::cout
+            << "NuclearInteraction::InitializeNuclearCrossSections: target nucleus? id="
+            << ptarg << std::endl;
         throw std::runtime_error(
             " target can not be handled by hadronic interaction model! ");
       }
@@ -96,7 +98,7 @@ namespace corsika::sibyll {
       for (unsigned int i = 0; i < GetNEnergyBins(); ++i) {
         // hard coded energy grid, has to be aligned to definition in signuc2!!, no
         // comment..
-        const corsika::units::si::HEPEnergyType Ecm = pow(10., 1. + 1. * i) * 1_GeV;
+        const HEPEnergyType Ecm = pow(10., 1. + 1. * i) * 1_GeV;
         // get p-p cross sections
         auto const protonId = Code::Proton;
         auto const [siginel, sigela] =
@@ -115,8 +117,8 @@ namespace corsika::sibyll {
         }
       }
     }
-    std::cout << "NuclearInteraction: cross sections for " << targetComponentsIndex_.size()
-         << " components initialized!" << std::endl;
+    std::cout << "NuclearInteraction: cross sections for "
+              << targetComponentsIndex_.size() << " components initialized!" << std::endl;
     for (auto& ptarg : allElementsInUniverse) {
       std::cout << "cross section table: " << ptarg << std::endl;
       PrintCrossSectionTable(ptarg);
@@ -125,7 +127,7 @@ namespace corsika::sibyll {
 
   template <>
   void NuclearInteraction<corsika::setup::SetupEnvironment>::Init() {
-  
+
     // initialize hadronic interaction module
     // TODO: safe to run multiple initializations?
     if (!hadronicInteraction_.WasInitialized()) hadronicInteraction_.Init();
@@ -145,13 +147,12 @@ namespace corsika::sibyll {
   }
 
   template <>
-  corsika::units::si::CrossSectionType NuclearInteraction<corsika::setup::SetupEnvironment>::ReadCrossSectionTable(
-      const int ia, corsika::Code pTarget, corsika::units::si::HEPEnergyType elabnuc) {
-
-    using namespace corsika::units::si;
+  CrossSectionType
+  NuclearInteraction<corsika::setup::SetupEnvironment>::ReadCrossSectionTable(
+      const int ia, corsika::Code pTarget, HEPEnergyType elabnuc) {
 
     const int ib = targetComponentsIndex_.at(pTarget) + 1; // table index in fortran
-    auto const ECoMNuc = sqrt(2. * corsika::units::constants::nucleonMass * elabnuc);
+    auto const ECoMNuc = sqrt(2. * constants::nucleonMass * elabnuc);
     if (ECoMNuc < GetMinEnergyPerNucleonCoM() || ECoMNuc > GetMaxEnergyPerNucleonCoM())
       throw std::runtime_error("NuclearInteraction: energy outside tabulated range!");
     const double e0 = elabnuc / 1_GeV;
@@ -165,11 +166,9 @@ namespace corsika::sibyll {
   // TODO: remove elastic cross section?
   template <>
   template <typename TParticle>
-  std::tuple<corsika::units::si::CrossSectionType, corsika::units::si::CrossSectionType>
-  NuclearInteraction<corsika::setup::SetupEnvironment>::GetCrossSection(const TParticle& vP,
-                                                        const corsika::Code TargetId) {
-
-    using namespace corsika::units::si;
+  std::tuple<CrossSectionType, CrossSectionType>
+  NuclearInteraction<corsika::setup::SetupEnvironment>::GetCrossSection(
+      const TParticle& vP, const corsika::Code TargetId) {
 
     if (vP.GetPID() != corsika::Code::Nucleus)
       throw std::runtime_error(
@@ -178,16 +177,17 @@ namespace corsika::sibyll {
     unsigned int const iBeamA = vP.GetNuclearA();
     HEPEnergyType LabEnergyPerNuc = vP.GetEnergy() / iBeamA;
     std::cout << "NuclearInteraction: GetCrossSection: called with: beamNuclA= " << iBeamA
-         << " TargetId= " << TargetId << " LabEnergyPerNuc= " << LabEnergyPerNuc / 1_GeV
-         << std::endl;
+              << " TargetId= " << TargetId
+              << " LabEnergyPerNuc= " << LabEnergyPerNuc / 1_GeV << std::endl;
 
     // use nuclib to calc. nuclear cross sections
     // TODO: for now assumes air with hard coded composition
     // extend to arbitrary mixtures, requires smarter initialization
     // get nuclib projectile code: nucleon number
     if (iBeamA > GetMaxNucleusAProjectile() || iBeamA < 2) {
-      std::cout << "NuclearInteraction: beam nucleus outside allowed range for NUCLIB!" << std::endl
-           << "A=" << iBeamA << std::endl;
+      std::cout << "NuclearInteraction: beam nucleus outside allowed range for NUCLIB!"
+                << std::endl
+                << "A=" << iBeamA << std::endl;
       throw std::runtime_error(
           "NuclearInteraction: GetCrossSection: beam nucleus outside allowed range for "
           "NUCLIB!");
@@ -206,10 +206,8 @@ namespace corsika::sibyll {
 
   template <>
   template <typename TParticle>
-  corsika::units::si::GrammageType NuclearInteraction<corsika::setup::SetupEnvironment>::GetInteractionLength(
-                               const TParticle& vP) {
-
-    using namespace corsika::units::si;
+  GrammageType NuclearInteraction<corsika::setup::SetupEnvironment>::GetInteractionLength(
+      const TParticle& vP) {
 
     // coordinate system, get global frame of reference
     CoordinateSystem& rootCS =
@@ -235,7 +233,7 @@ namespace corsika::sibyll {
     corsika::MomentumVector pTarget(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
 
     // total momentum and energy
-    HEPEnergyType Elab = vP.GetEnergy() + corsika::units::constants::nucleonMass;
+    HEPEnergyType Elab = vP.GetEnergy() + constants::nucleonMass;
     int const nuclA = vP.GetNuclearA();
     auto const ElabNuc = vP.GetEnergy() / nuclA;
 
@@ -246,14 +244,14 @@ namespace corsika::sibyll {
     // calculate cm. energy
     const HEPEnergyType ECoM = sqrt(
         (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy
-    auto const ECoMNN = sqrt(2. * ElabNuc * corsika::units::constants::nucleonMass);
+    auto const ECoMNN = sqrt(2. * ElabNuc * constants::nucleonMass);
     std::cout << "NuclearInteraction: LambdaInt: \n"
-         << " input energy: " << Elab / 1_GeV << std::endl
-         << " input energy CoM: " << ECoM / 1_GeV << std::endl
-         << " beam pid:" << corsikaBeamId << std::endl
-         << " beam A: " << nuclA << std::endl
-         << " input energy per nucleon: " << ElabNuc / 1_GeV << std::endl
-         << " input energy CoM per nucleon: " << ECoMNN / 1_GeV << std::endl;
+              << " input energy: " << Elab / 1_GeV << std::endl
+              << " input energy CoM: " << ECoM / 1_GeV << std::endl
+              << " beam pid:" << corsikaBeamId << std::endl
+              << " beam A: " << nuclA << std::endl
+              << " input energy per nucleon: " << ElabNuc / 1_GeV << std::endl
+              << " input energy CoM per nucleon: " << ECoMNN / 1_GeV << std::endl;
     //      throw std::runtime_error("stop here");
 
     // energy limits
@@ -280,26 +278,26 @@ namespace corsika::sibyll {
       for (auto const targetId : mediumComposition.GetComponents()) {
         i++;
         std::cout << "NuclearInteraction: get interaction length for target: " << targetId
-             << std::endl;
+                  << std::endl;
         auto const [productionCrossSection, elaCrossSection] =
             GetCrossSection(vP, targetId);
         [[maybe_unused]] auto& dummy_elaCrossSection = elaCrossSection;
 
         std::cout << "NuclearInteraction: "
-             << "IntLength: nuclib return (mb): " << productionCrossSection / 1_mb
-             << std::endl;
+                  << "IntLength: nuclib return (mb): " << productionCrossSection / 1_mb
+                  << std::endl;
         weightedProdCrossSection += w[i] * productionCrossSection;
       }
       std::cout << "NuclearInteraction: "
-           << "IntLength: weighted CrossSection (mb): " << weightedProdCrossSection / 1_mb
-           << std::endl;
+                << "IntLength: weighted CrossSection (mb): "
+                << weightedProdCrossSection / 1_mb << std::endl;
 
       // calculate interaction length in medium
       GrammageType const int_length = mediumComposition.GetAverageMassNumber() *
-                                      corsika::units::constants::u / weightedProdCrossSection;
+                                      constants::u / weightedProdCrossSection;
       std::cout << "NuclearInteraction: "
-           << "interaction length (g/cm2): " << int_length * (1_cm * 1_cm / (0.001_kg))
-           << std::endl;
+                << "interaction length (g/cm2): "
+                << int_length * (1_cm * 1_cm / (0.001_kg)) << std::endl;
 
       return int_length;
     } else {
@@ -309,10 +307,10 @@ namespace corsika::sibyll {
 
   template <>
   template <typename TProjectile>
-  corsika::EProcessReturn NuclearInteraction<corsika::setup::SetupEnvironment>::DoInteraction(
-       TProjectile& vP) {
+  corsika::EProcessReturn
+  NuclearInteraction<corsika::setup::SetupEnvironment>::DoInteraction(TProjectile& vP) {
 
-    using namespace corsika::units::si;
+    using namespace si;
 
     // this routine superimposes different nucleon-nucleon interactions
     // in a nucleus-nucleus interaction, based the SIBYLL routine SIBNUC
@@ -342,7 +340,8 @@ namespace corsika::sibyll {
     Point pOrig = vP.GetPosition();
     TimeType tOrig = vP.GetTime();
 
-    std::cout << "Interaction: position of interaction: " << pOrig.GetCoordinates() << std::endl;
+    std::cout << "Interaction: position of interaction: " << pOrig.GetCoordinates()
+              << std::endl;
     std::cout << "Interaction: time: " << tOrig << std::endl;
 
     // projectile nucleon number
@@ -357,29 +356,29 @@ namespace corsika::sibyll {
     const FourVector PprojLab(eProjectileLab, pProjectileLab);
 
     std::cout << "NuclearInteraction: eProj lab: " << eProjectileLab / 1_GeV << std::endl
-         << "NuclearInteraction: pProj lab: " << pProjectileLab.GetComponents() / 1_GeV
-         << std::endl;
+              << "NuclearInteraction: pProj lab: "
+              << pProjectileLab.GetComponents() / 1_GeV << std::endl;
 
     // define projectile nucleon
     HEPEnergyType const eProjectileNucLab = vP.GetEnergy() / kAProj;
     auto const pProjectileNucLab = vP.GetMomentum() / kAProj;
     const FourVector PprojNucLab(eProjectileNucLab, pProjectileNucLab);
 
-    std::cout << "NuclearInteraction: eProjNucleon lab: " << eProjectileNucLab / 1_GeV << std::endl
-         << "NuclearInteraction: pProjNucleon lab: "
-         << pProjectileNucLab.GetComponents() / 1_GeV << std::endl;
+    std::cout << "NuclearInteraction: eProjNucleon lab: " << eProjectileNucLab / 1_GeV
+              << std::endl
+              << "NuclearInteraction: pProjNucleon lab: "
+              << pProjectileNucLab.GetComponents() / 1_GeV << std::endl;
 
     // define target
     // always a nucleon
     // target is always at rest
-    const auto eTargetNucLab = 0_GeV + corsika::units::constants::nucleonMass;
-    const auto pTargetNucLab =
-        corsika::MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV);
+    const auto eTargetNucLab = 0_GeV + constants::nucleonMass;
+    const auto pTargetNucLab = corsika::MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV);
     const FourVector PtargNucLab(eTargetNucLab, pTargetNucLab);
 
     std::cout << "NuclearInteraction: etarget lab: " << eTargetNucLab / 1_GeV << std::endl
-         << "NuclearInteraction: ptarget lab: " << pTargetNucLab.GetComponents() / 1_GeV
-         << std::endl;
+              << "NuclearInteraction: ptarget lab: "
+              << pTargetNucLab.GetComponents() / 1_GeV << std::endl;
 
     // center-of-mass energy in nucleon-nucleon frame
     auto const PtotNN4 = PtargNucLab + PprojNucLab;
@@ -388,13 +387,13 @@ namespace corsika::sibyll {
 
     if (!hadronicInteraction_.IsValidCoMEnergy(EcmNN)) {
       std::cout << "NuclearInteraction: nuc-nuc. CoM energy too low for hadronic "
-              "interaction model!"
-           << std::endl;
+                   "interaction model!"
+                << std::endl;
       throw std::runtime_error("NuclearInteraction: DoInteraction: energy too low!");
     }
 
     // define boost to NUCLEON-NUCLEON frame
-    COMBoost const boost(PprojNucLab, corsika::units::constants::nucleonMass);
+    COMBoost const boost(PprojNucLab, constants::nucleonMass);
     // boost projecticle
     auto const PprojNucCoM = boost.toCoM(PprojNucLab);
 
@@ -402,13 +401,15 @@ namespace corsika::sibyll {
     auto const PtargNucCoM = boost.toCoM(PtargNucLab);
 
     std::cout << "Interaction: ebeam CoM: " << PprojNucCoM.GetTimeLikeComponent() / 1_GeV
-         << std::endl
-         << "Interaction: pbeam CoM: "
-         << PprojNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << std::endl;
-    std::cout << "Interaction: etarget CoM: " << PtargNucCoM.GetTimeLikeComponent() / 1_GeV
-         << std::endl
-         << "Interaction: ptarget CoM: "
-         << PtargNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << std::endl;
+              << std::endl
+              << "Interaction: pbeam CoM: "
+              << PprojNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV
+              << std::endl;
+    std::cout << "Interaction: etarget CoM: "
+              << PtargNucCoM.GetTimeLikeComponent() / 1_GeV << std::endl
+              << "Interaction: ptarget CoM: "
+              << PtargNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV
+              << std::endl;
 
     // sample target nucleon number
     //
@@ -454,7 +455,8 @@ namespace corsika::sibyll {
     // end of target sampling
 
     // superposition
-    std::cout << "NuclearInteraction: sampling nuc. multiple interaction structure.. " << std::endl;
+    std::cout << "NuclearInteraction: sampling nuc. multiple interaction structure.. "
+              << std::endl;
     // get nucleon-nucleon cross section
     // (needed to determine number of nucleon-nucleon scatterings)
     const auto protonId = corsika::Proton::GetCode();
@@ -467,13 +469,13 @@ namespace corsika::sibyll {
     int_nuc_(kATarget, kAProj, sigProd, sigEla);
 
     std::cout << "number of nucleons in target           : " << kATarget << std::endl
-         << "number of wounded nucleons in target   : " << cnucms_.na << std::endl
-         << "number of nucleons in projectile       : " << kAProj << std::endl
-         << "number of wounded nucleons in project. : " << cnucms_.nb << std::endl
-         << "number of inel. nuc.-nuc. interactions : " << cnucms_.ni << std::endl
-         << "number of elastic nucleons in target   : " << cnucms_.nael << std::endl
-         << "number of elastic nucleons in project. : " << cnucms_.nbel << std::endl
-         << "impact parameter: " << cnucms_.b << std::endl;
+              << "number of wounded nucleons in target   : " << cnucms_.na << std::endl
+              << "number of nucleons in projectile       : " << kAProj << std::endl
+              << "number of wounded nucleons in project. : " << cnucms_.nb << std::endl
+              << "number of inel. nuc.-nuc. interactions : " << cnucms_.ni << std::endl
+              << "number of elastic nucleons in target   : " << cnucms_.nael << std::endl
+              << "number of elastic nucleons in project. : " << cnucms_.nbel << std::endl
+              << "impact parameter: " << cnucms_.b << std::endl;
 
     // calculate fragmentation
     std::cout << "calculating nuclear fragments.." << std::endl;
@@ -499,8 +501,8 @@ namespace corsika::sibyll {
     std::cout << "number of fragments: " << nFragments << std::endl;
     for (int j = 0; j < nFragments; ++j)
       std::cout << "fragment: " << j << " A=" << AFragments[j]
-           << " px=" << fragments_.ppp[j][0] << " py=" << fragments_.ppp[j][1]
-           << " pz=" << fragments_.ppp[j][2] << std::endl;
+                << " px=" << fragments_.ppp[j][0] << " py=" << fragments_.ppp[j][1]
+                << " pz=" << fragments_.ppp[j][2] << std::endl;
 
     std::cout << "adding nuclear fragments to particle stack.." << std::endl;
     // put nuclear fragments on corsika stack
@@ -535,22 +537,21 @@ namespace corsika::sibyll {
       auto const Plab = PprojLab * mass_ratio;
 
       std::cout << "NuclearInteraction: fragment momentum: "
-           << Plab.GetSpaceLikeComponents().GetComponents() / 1_GeV << std::endl;
+                << Plab.GetSpaceLikeComponents().GetComponents() / 1_GeV << std::endl;
 
       if (nuclA == 1)
         // add nucleon
-        vP.AddSecondary(
-            std::tuple<corsika::Code, corsika::units::si::HEPEnergyType, corsika::MomentumVector,
-                  corsika::Point, corsika::units::si::TimeType>{
-                specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(),
-                pOrig, tOrig});
+        vP.AddSecondary(std::tuple<corsika::Code, si::HEPEnergyType,
+                                   corsika::MomentumVector, corsika::Point, si::TimeType>{
+            specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig,
+            tOrig});
       else
         // add nucleus
-        vP.AddSecondary(std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                              corsika::MomentumVector, corsika::Point,
-                              corsika::units::si::TimeType, unsigned short, unsigned short>{
-            specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig,
-            tOrig, nuclA, nuclZ});
+        vP.AddSecondary(
+            std::tuple<corsika::Code, si::HEPEnergyType, corsika::MomentumVector,
+                       corsika::Point, si::TimeType, unsigned short, unsigned short>{
+                specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(),
+                pOrig, tOrig, nuclA, nuclZ});
     }
 
     // add elastic nucleons to corsika stack
@@ -567,11 +568,10 @@ namespace corsika::sibyll {
       const double mass_ratio = corsika::GetMass(elaNucCode) / ProjMass;
       auto const Plab = PprojLab * mass_ratio;
 
-      vP.AddSecondary(
-          std::tuple<corsika::Code, corsika::units::si::HEPEnergyType, corsika::MomentumVector,
-                corsika::Point, corsika::units::si::TimeType>{
-              elaNucCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(),
-              pOrig, tOrig});
+      vP.AddSecondary(std::tuple<corsika::Code, si::HEPEnergyType,
+                                 corsika::MomentumVector, corsika::Point, si::TimeType>{
+          elaNucCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig,
+          tOrig});
     }
 
     // add inelastic interactions
@@ -582,8 +582,8 @@ namespace corsika::sibyll {
       // temporarily add to stack, will be removed after interaction in DoInteraction
       std::cout << "inelastic interaction no. " << j << std::endl;
       auto inelasticNucleon = vP.AddSecondary(
-          std::tuple<corsika::Code, corsika::units::si::HEPEnergyType, corsika::MomentumVector,
-                corsika::Point, corsika::units::si::TimeType>{
+          std::tuple<corsika::Code, si::HEPEnergyType, corsika::MomentumVector,
+                     corsika::Point, si::TimeType>{
               pCode, PprojNucLab.GetTimeLikeComponent(),
               PprojNucLab.GetSpaceLikeComponents(), pOrig, tOrig});
       // create inelastic interaction
@@ -597,4 +597,3 @@ namespace corsika::sibyll {
   }
 
 } // namespace corsika::sibyll
-
diff --git a/corsika/detail/modules/sibyll/ParticleConversion.inl b/corsika/detail/modules/sibyll/ParticleConversion.inl
index fbc978d2a0264f3c65bfff71420d3b898bcd6939..e458f36ee31f0b9ff623d3af899b23c3e24e97f5 100644
--- a/corsika/detail/modules/sibyll/ParticleConversion.inl
+++ b/corsika/detail/modules/sibyll/ParticleConversion.inl
@@ -10,12 +10,7 @@
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 
-using namespace corsika::sibyll;
-
-corsika::units::si::HEPMassType corsika::sibyll::GetSibyllMass(
-    corsika::Code const pCode) {
-  using namespace corsika::units;
-  using namespace corsika::units::si;
+corsika::HEPMassType corsika::sibyll::GetSibyllMass(corsika::Code const pCode) {
   if (pCode == corsika::Code::Nucleus)
     throw std::runtime_error("Cannot GetMass() of particle::Nucleus -> unspecified");
   auto sCode = ConvertToSibyllRaw(pCode);
diff --git a/corsika/detail/modules/urqmd/UrQMD.inl b/corsika/detail/modules/urqmd/UrQMD.inl
index eaacb3fb8e9b53fbd017100bdc013a4e643cf457..a6dfd53cda0a18da00bf8923e9aa98d409bbcfde 100644
--- a/corsika/detail/modules/urqmd/UrQMD.inl
+++ b/corsika/detail/modules/urqmd/UrQMD.inl
@@ -20,21 +20,21 @@
 #include <algorithm>
 #include <functional>
 #include <iostream>
-#include <random>
+
+#include <urqmd.hpp>
 
 namespace corsika::urqmd {
 
-  UrQMD::UrQMD() { iniurqmdc8_(); }
+  UrQMD::UrQMD() { ::urqmd::iniurqmdc8_(); }
 
   using SetupStack = corsika::setup::Stack;
   using SetupParticle = corsika::setup::Stack::StackIterator;
   using SetupProjectile = corsika::setup::StackView::StackIterator;
 
-  corsika::units::si::CrossSectionType UrQMD::GetCrossSection(
-      corsika::Code vProjectileCode, corsika::Code vTargetCode,
-      corsika::units::si::HEPEnergyType vLabEnergy, int vAProjectile = 1) {
-
-    using namespace units::si;
+  CrossSectionType UrQMD::GetCrossSection(corsika::Code vProjectileCode,
+                                          corsika::Code vTargetCode,
+                                          HEPEnergyType vLabEnergy,
+                                          int vAProjectile = 1) {
 
     // the following is a translation of ptsigtot() into C++
     if (vProjectileCode != corsika::Code::Nucleus &&
@@ -42,36 +42,36 @@ namespace corsika::urqmd {
       auto const mProj = corsika::GetMass(vProjectileCode);
       auto const mTar = corsika::GetMass(vTargetCode);
       double sqrtS =
-          sqrt(units::si::detail::static_pow<2>(mProj) +
-               units::si::detail::static_pow<2>(mTar) + 2 * vLabEnergy * mTar) *
+          sqrt(static_pow<2>(mProj) + static_pow<2>(mTar) + 2 * vLabEnergy * mTar) *
           (1 / 1_GeV);
 
       // we must set some UrQMD globals first...
       auto const [ityp, iso3] = ConvertToUrQMD(vProjectileCode);
-      inputs_.spityp[0] = ityp;
-      inputs_.spiso3[0] = iso3;
+      ::urqmd::inputs_.spityp[0] = ityp;
+      ::urqmd::inputs_.spiso3[0] = iso3;
 
       auto const [itypTar, iso3Tar] = ConvertToUrQMD(vTargetCode);
-      inputs_.spityp[1] = itypTar;
-      inputs_.spiso3[1] = iso3Tar;
+      ::urqmd::inputs_.spityp[1] = itypTar;
+      ::urqmd::inputs_.spiso3[1] = iso3Tar;
 
       int one = 1;
       int two = 2;
-      return sigtot_(one, two, sqrtS) * 1_mb;
+      return ::urqmd::sigtot_(one, two, sqrtS) * 1_mb;
     } else {
       int const Ap = vAProjectile;
       int const At = IsNucleus(vTargetCode) ? corsika::GetNucleusA(vTargetCode) : 1;
 
-      double const maxImpact = nucrad_(Ap) + nucrad_(At) + 2 * options_.CTParam[30 - 1];
-      return 10_mb * M_PI * units::si::detail::static_pow<2>(maxImpact);
+      double const maxImpact = ::urqmd::nucrad_(Ap) + ::urqmd::nucrad_(At) +
+                               2 * ::urqmd::options_.CTParam[30 - 1];
+      return 10_mb * M_PI * static_pow<2>(maxImpact);
       // is a constant cross-section really reasonable?
     }
   }
 
   template <typename TParticle> // need template here, as this is called both with
                                 // SetupParticle as well as SetupProjectile
-  corsika::units::si::CrossSectionType UrQMD::GetCrossSection(
-      TParticle const& vProjectile, corsika::Code vTargetCode) const {
+  CrossSectionType UrQMD::GetCrossSection(TParticle const& vProjectile,
+                                          corsika::Code vTargetCode) const {
     // TODO: return 0 for non-hadrons?
 
     auto const projectileCode = vProjectile.GetPID();
@@ -104,10 +104,7 @@ namespace corsika::urqmd {
                      vCode) != std::cend(validProjectileCodes);
   }
 
-  corsika::units::si::GrammageType UrQMD::GetInteractionLength(
-      SetupParticle& vParticle) const {
-
-    using namespace units::si;
+  GrammageType UrQMD::GetInteractionLength(SetupParticle& vParticle) const {
 
     if (!CanInteract(vParticle.GetPID())) {
       // we could do the canInteract check in GetCrossSection, too but if
@@ -119,18 +116,15 @@ namespace corsika::urqmd {
         vParticle.GetNode()->GetModelProperties().GetNuclearComposition();
     using namespace std::placeholders;
 
-    corsika::units::si::CrossSectionType const weightedProdCrossSection =
-        mediumComposition.WeightedSum(
-            std::bind(&UrQMD::GetCrossSection<decltype(vParticle)>, this, vParticle, _1));
+    CrossSectionType const weightedProdCrossSection = mediumComposition.WeightedSum(
+        std::bind(&UrQMD::GetCrossSection<decltype(vParticle)>, this, vParticle, _1));
 
-    return mediumComposition.GetAverageMassNumber() * units::constants::u /
+    return mediumComposition.GetAverageMassNumber() * constants::u /
            weightedProdCrossSection;
   }
 
   corsika::EProcessReturn UrQMD::DoInteraction(SetupProjectile& vProjectile) {
 
-    using namespace units::si;
-
     auto projectileCode = vProjectile.GetPID();
     auto const projectileEnergyLab = vProjectile.GetEnergy();
     auto const& projectileMomentumLab = vProjectile.GetMomentum();
@@ -142,7 +136,7 @@ namespace corsika::urqmd {
         vProjectile.GetNode()->GetModelProperties().GetNuclearComposition();
     auto const componentCrossSections = std::invoke([&]() {
       auto const& components = mediumComposition.GetComponents();
-      std::vector<corsika::units::si::CrossSectionType> crossSections;
+      std::vector<CrossSectionType> crossSections;
       crossSections.reserve(components.size());
 
       for (auto const c : components) {
@@ -156,30 +150,34 @@ namespace corsika::urqmd {
     auto const targetA = corsika::GetNucleusA(targetCode);
     auto const targetZ = corsika::GetNucleusZ(targetCode);
 
-    inputs_.nevents = 1;
-    sys_.eos = 0; // could be configurable in principle
-    inputs_.outsteps = 1;
-    sys_.nsteps = 1;
+    ::urqmd::inputs_.nevents = 1;
+    ::urqmd::sys_.eos = 0; // could be configurable in principle
+    ::urqmd::inputs_.outsteps = 1;
+    ::urqmd::sys_.nsteps = 1;
 
     // initialization regarding projectile
     if (corsika::Code::Nucleus == projectileCode) {
       // is this everything?
-      inputs_.prspflg = 0;
+      ::urqmd::inputs_.prspflg = 0;
 
-      sys_.Ap = vProjectile.GetNuclearA();
-      sys_.Zp = vProjectile.GetNuclearZ();
-      rsys_.ebeam = (projectileEnergyLab - vProjectile.GetMass()) * (1 / 1_GeV) /
-                    vProjectile.GetNuclearA();
+      ::urqmd::sys_.Ap = vProjectile.GetNuclearA();
+      ::urqmd::sys_.Zp = vProjectile.GetNuclearZ();
+      ::urqmd::rsys_.ebeam = (projectileEnergyLab - vProjectile.GetMass()) * (1 / 1_GeV) /
+                             vProjectile.GetNuclearA();
 
-      rsys_.bdist = nucrad_(targetA) + nucrad_(sys_.Ap) + 2 * options_.CTParam[30 - 1];
+      ::urqmd::rsys_.bdist = ::urqmd::nucrad_(targetA) +
+                             ::urqmd::nucrad_(::urqmd::sys_.Ap) +
+                             2 * ::urqmd::options_.CTParam[30 - 1];
 
       int const id = 1;
-      cascinit_(sys_.Zp, sys_.Ap, id);
+      ::urqmd::cascinit_(::urqmd::sys_.Zp, ::urqmd::sys_.Ap, id);
     } else {
-      inputs_.prspflg = 1;
-      sys_.Ap = 1; // even for non-baryons this has to be set, see vanilla UrQMD.f
-      rsys_.bdist = nucrad_(targetA) + nucrad_(1) + 2 * options_.CTParam[30 - 1];
-      rsys_.ebeam = (projectileEnergyLab - vProjectile.GetMass()) * (1 / 1_GeV);
+      ::urqmd::inputs_.prspflg = 1;
+      ::urqmd::sys_.Ap =
+          1; // even for non-baryons this has to be set, see vanilla UrQMD.f
+      ::urqmd::rsys_.bdist = ::urqmd::nucrad_(targetA) + ::urqmd::nucrad_(1) +
+                             2 * ::urqmd::options_.CTParam[30 - 1];
+      ::urqmd::rsys_.ebeam = (projectileEnergyLab - vProjectile.GetMass()) * (1 / 1_GeV);
 
       if (projectileCode == corsika::Code::K0Long) {
         projectileCode = fBooleanDist(fRNG) ? corsika::Code::K0 : corsika::Code::K0Bar;
@@ -189,43 +187,44 @@ namespace corsika::urqmd {
 
       auto const [ityp, iso3] = ConvertToUrQMD(projectileCode);
       // todo: conversion of K_long/short into strong eigenstates;
-      inputs_.spityp[0] = ityp;
-      inputs_.spiso3[0] = iso3;
+      ::urqmd::inputs_.spityp[0] = ityp;
+      ::urqmd::inputs_.spiso3[0] = iso3;
     }
 
     // initilazation regarding target
     if (corsika::IsNucleus(targetCode)) {
-      sys_.Zt = targetZ;
-      sys_.At = targetA;
-      inputs_.trspflg = 0; // nucleus as target
+      ::urqmd::sys_.Zt = targetZ;
+      ::urqmd::sys_.At = targetA;
+      ::urqmd::inputs_.trspflg = 0; // nucleus as target
       int const id = 2;
-      cascinit_(sys_.Zt, sys_.At, id);
+      ::urqmd::cascinit_(::urqmd::sys_.Zt, ::urqmd::sys_.At, id);
     } else {
-      inputs_.trspflg = 1; // special particle as target
+      ::urqmd::inputs_.trspflg = 1; // special particle as target
       auto const [ityp, iso3] = ConvertToUrQMD(targetCode);
-      inputs_.spityp[1] = ityp;
-      inputs_.spiso3[1] = iso3;
+      ::urqmd::inputs_.spityp[1] = ityp;
+      ::urqmd::inputs_.spiso3[1] = iso3;
     }
 
     int iflb = 0; // flag for retrying interaction in case of empty event, 0 means retry
-    urqmd_(iflb);
+    ::urqmd::urqmd_(iflb);
 
     // now retrieve secondaries from UrQMD
     auto const& originalCS = projectileMomentumLab.GetCoordinateSystem();
     corsika::CoordinateSystem const zAxisFrame =
         originalCS.RotateToZ(projectileMomentumLab);
 
-    for (int i = 0; i < sys_.npart; ++i) {
-      auto code = ConvertFromUrQMD(isys_.ityp[i], isys_.iso3[i]);
+    for (int i = 0; i < ::urqmd::sys_.npart; ++i) {
+      auto code = ConvertFromUrQMD(::urqmd::isys_.ityp[i], ::urqmd::isys_.iso3[i]);
       if (code == corsika::Code::K0 || code == corsika::Code::K0Bar) {
         code = fBooleanDist(fRNG) ? corsika::Code::K0Short : corsika::Code::K0Long;
       }
 
       // "coor_.p0[i] * 1_GeV" is likely off-shell as UrQMD doesn't preserve masses well
       auto momentum = corsika::Vector(
-          zAxisFrame, corsika::QuantityVector<dimensionless_d>{coor_.px[i], coor_.py[i],
-                                                                coor_.pz[i]} *
-                          1_GeV);
+          zAxisFrame,
+          corsika::QuantityVector<dimensionless_d>{
+              ::urqmd::coor_.px[i], ::urqmd::coor_.py[i], ::urqmd::coor_.pz[i]} *
+              1_GeV);
 
       auto const energy = sqrt(momentum.squaredNorm() + square(corsika::GetMass(code)));
 
@@ -233,31 +232,21 @@ namespace corsika::urqmd {
       std::cout << i << " " << code << " " << momentum.GetComponents() << std::endl;
 
       vProjectile.AddSecondary(
-          std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                     corsika::MomentumVector, corsika::Point, corsika::units::si::TimeType>{
-              code, energy, momentum, projectilePosition, projectileTime});
+          std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector,
+                     corsika::Point, TimeType>{code, energy, momentum, projectilePosition,
+                                               projectileTime});
     }
 
-    std::cout << "UrQMD generated " << sys_.npart << " secondaries!" << std::endl;
+    std::cout << "UrQMD generated " << ::urqmd::sys_.npart << " secondaries!"
+              << std::endl;
 
     return corsika::EProcessReturn::eOk;
   }
 
-  /**
-   * the random number generator function of UrQMD
-   */
-  double ranf_(int&) {
-    static corsika::RNG& rng =
-        corsika::RNGManager::GetInstance().GetRandomStream("UrQMD");
-    static std::uniform_real_distribution<double> dist;
-
-    return dist(rng);
-  }
-
   corsika::Code ConvertFromUrQMD(int vItyp, int vIso3) {
     int const pdgInt =
-        pdgid_(vItyp, vIso3); // use the conversion function provided by UrQMD
-    if (pdgInt == 0) {        // pdgid_ returns 0 on error
+        ::urqmd::pdgid_(vItyp, vIso3); // use the conversion function provided by UrQMD
+    if (pdgInt == 0) {                 // ::urqmd::pdgid_ returns 0 on error
       throw std::runtime_error("UrQMD pdgid() returned 0");
     }
     auto const pdg = static_cast<corsika::PDGCode>(pdgInt);
diff --git a/corsika/framework/core/CMakeLists.txt b/corsika/framework/core/CMakeLists.txt
deleted file mode 100644
index c922c93da0b9cf6b326199a6bdc0c202d7ffcb37..0000000000000000000000000000000000000000
--- a/corsika/framework/core/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-add_custom_command (
-  OUTPUT  ${PROJECT_BINARY_DIR}/GeneratedParticleProperties.inc
-          ${PROJECT_BINARY_DIR}/particle_db.pkl
-  COMMAND ${PROJECT_SOURCE_DIR}/Framework/Particles/pdxml_reader.py 
-          ${PROJECT_SOURCE_DIR}/Framework/Particles/ParticleData.xml
-          ${PROJECT_SOURCE_DIR}/Framework/Particles/NuclearData.xml
-          ${PROJECT_SOURCE_DIR}/Framework/Particles/ParticleClassNames.xml
-  DEPENDS pdxml_reader.py
-          ParticleData.xml
-          NuclearData.xml
-          ParticleClassNames.xml
-  WORKING_DIRECTORY
-          ${PROJECT_BINARY_DIR}/
-  COMMENT "Read PYTHIA8 particle data and produce C++ source code GeneratedParticleProperties.inc"
-  VERBATIM
-  )
-
-add_dependencies (CORSIKA8 ${PROJECT_BINARY_DIR}/Framework/Particles/GeneratedParticleProperties.inc)
diff --git a/corsika/framework/core/Cascade.hpp b/corsika/framework/core/Cascade.hpp
index 276a454bd66b0f018b46ca2707b9f8fce0ffe26b..e66448d6f59527dbfe220d1ffe2788fae3aa0a35 100644
--- a/corsika/framework/core/Cascade.hpp
+++ b/corsika/framework/core/Cascade.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,20 +8,24 @@
 
 #pragma once
 
-#include <cassert>
-#include <cmath>
-#include <limits>
+#include <corsika/framework/process/ProcessReturn.hpp>
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/random/ExponentialDistribution.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
 #include <corsika/framework/random/UniformRealDistribution.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp>
 #include <corsika/framework/stack/SecondaryView.hpp>
 #include <corsika/media/Environment.hpp>
+
 #include <corsika/setup/SetupStack.hpp>
 #include <corsika/setup/SetupTrajectory.hpp>
 
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <type_traits>
+
 /**
  * The cascade namespace assembles all objects needed to simulate full particles cascades.
  */
diff --git a/corsika/framework/core/ParticleProperties.hpp b/corsika/framework/core/ParticleProperties.hpp
index 759224e76828c88b376153561c0a7b579c8e071d..b4db8bd04948babd876cfe7a49169cc02e6493be 100644
--- a/corsika/framework/core/ParticleProperties.hpp
+++ b/corsika/framework/core/ParticleProperties.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -40,11 +40,11 @@ namespace corsika {
 
   // forward declarations to be used in GeneratedParticleProperties
   int16_t constexpr GetChargeNumber(Code const);
-  corsika::units::si::ElectricChargeType constexpr GetCharge(Code const);
-  corsika::units::si::HEPMassType constexpr GetMass(Code const);
+  ElectricChargeType constexpr GetCharge(Code const);
+  HEPMassType constexpr GetMass(Code const);
   PDGCode constexpr GetPDG(Code const);
   constexpr std::string const& GetName(Code const);
-  corsika::units::si::TimeType constexpr GetLifetime(Code const);
+  TimeType constexpr GetLifetime(Code const);
 
   bool constexpr IsNucleus(Code const);
   bool constexpr IsHadron(Code const);
@@ -61,7 +61,7 @@ namespace corsika::particles {
   /*!
    * returns mass of particle in natural units
    */
-  corsika::units::si::HEPMassType constexpr GetMass(Code const p) {
+  HEPMassType constexpr GetMass(Code const p) {
     if (p == Code::Nucleus)
       throw std::runtime_error("Cannot GetMass() of particle::Nucleus -> unspecified");
     return particle::detail::masses[static_cast<CodeIntType>(p)];
@@ -88,19 +88,18 @@ namespace corsika::particles {
   /*!
    * returns electric charge of particle, e.g. return 1.602e-19_C for a proton.
    */
-  corsika::units::si::ElectricChargeType constexpr GetCharge(Code const p) {
+  ElectricChargeType constexpr GetCharge(Code const p) {
     if (p == Code::Nucleus)
       throw std::runtime_error("Cannot GetCharge() of particle::Nucleus -> unspecified");
-    return GetChargeNumber(p) * corsika::units::constants::e;
+    return GetChargeNumber(p) * constants::e;
   }
 
   constexpr std::string const& GetName(Code const p) {
     return particle::detail::names[static_cast<CodeIntType>(p)];
   }
 
-  inline corsika::units::si::TimeType constexpr GetLifetime(Code const p) {
-    return particle::detail::lifetime[static_cast<CodeIntType>(p)] *
-           corsika::units::si::second;
+  inline TimeType constexpr GetLifetime(Code const p) {
+    return particle::detail::lifetime[static_cast<CodeIntType>(p)] * second;
   }
 
   inline bool constexpr IsHadron(Code const p) {
@@ -158,8 +157,7 @@ namespace corsika::particles {
   /**
    * Get mass of nucleus
    **/
-  inline corsika::units::si::HEPMassType constexpr GetNucleusMass(const int vA,
-                                                                  const int vZ) {
+  inline HEPMassType constexpr GetNucleusMass(const int vA, const int vZ) {
     return Proton::GetMass() * vZ + (vA - vZ) * Neutron::GetMass();
   }
 
diff --git a/corsika/framework/core/PhysicalConstants.hpp b/corsika/framework/core/PhysicalConstants.hpp
index f47b917e6919762d7b1c73a950192c086e7afe4b..026d93a115bdf369afaa1effdfff217593a1b88e 100644
--- a/corsika/framework/core/PhysicalConstants.hpp
+++ b/corsika/framework/core/PhysicalConstants.hpp
@@ -9,16 +9,25 @@
 
 #pragma once
 
-#include <phys/units/quantity.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 
-namespace corsika::units::constants {
+/**
+ * \file PhysicalConstants.hpp
+ *
+ * Constants are defined with static units, based on the package
+ * (namespace) phys::units, imported in PhysicsUnits.hpp
+ *
+ * \namespace corsika::constants
+ *
+ * Physical and mathematical constants with units.
+ */
+
+namespace corsika::constants {
 
   using namespace phys::units;
 
   // acceleration of free-fall, standard
-  constexpr phys::units::quantity<phys::units::acceleration_d> g_sub_n{
-      phys::units::Rep(9.80665L) * phys::units::meter /
-      phys::units::square(phys::units::second)};
+  constexpr quantity<acceleration_d> g_sub_n{Rep(9.80665L) * meter / square(second)};
 
   // Avogadro constant
   constexpr quantity<dimensions<0, 0, 0, 0, 0, -1>> N_sub_A{Rep(6.02214199e+23L) / mole};
@@ -63,4 +72,4 @@ namespace corsika::units::constants {
 
   // etc.
 
-} // namespace corsika::units::constants
+} // namespace corsika::constants
diff --git a/corsika/framework/core/PhysicalUnits.hpp b/corsika/framework/core/PhysicalUnits.hpp
index 543b56a148e6e353e10a678336f751ce34c2921c..6de5bd4d0352de65c6859c7009a550b9d8d6e330 100644
--- a/corsika/framework/core/PhysicalUnits.hpp
+++ b/corsika/framework/core/PhysicalUnits.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,12 +8,19 @@
 
 #pragma once
 
-#include <corsika/framework/core/PhysicalConstants.hpp>
-
-// FIXME: What package is this?
+// the templated static-unit package we use:
 #include <phys/units/io.hpp>
 #include <phys/units/quantity.hpp>
 
+#include <corsika/framework/core/PhysicalConstants.hpp>
+
+/**
+ * \file PhysicalUnits.hpp
+ *
+ * Import and extend the phys::units package. The SI units are also imported into the
+ * `\namespace corsika`, since they are used everywhere as integral part of the framework.
+ */
+
 /*
   It is essentially a bug of the phys/units package to define the
   operator<< not in the same namespace as the types it is working
@@ -24,10 +31,9 @@ namespace phys::units {
 } // namespace phys::units
 
 /**
- * @file PhysicalUnits
+ * \namespace corsika::units
  *
- * Add new units and types we need. Units are compile-time. Literals are
- * used for optimal coding style.
+ * Extension of the phys::units package.
  *
  */
 
@@ -44,10 +50,19 @@ namespace corsika::units {
   }
 } // namespace corsika::units
 
+/**
+ * \namespace corsika::units::si
+ *
+ * SI units as used mainly in CORSIKA8 as basedline.
+ *
+ */
+
 namespace corsika::units::si {
+
   using namespace phys::units;
   using namespace phys::units::literals;
   using namespace phys::units::io;
+
   using phys::units::io::operator<<;
 
   /// defining momentum you suckers
@@ -78,8 +93,6 @@ namespace corsika::units::si {
       phys::units::quantity<phys::units::dimensions<0, 0, -1>, double>;
   using InverseGrammageType =
       phys::units::quantity<phys::units::dimensions<2, -1, 0>, double>;
-  using MagneticFluxType =
-      phys::units::quantity<phys::units::magnetic_flux_density_d, double>;
 
   template <typename DimFrom, typename DimTo>
   auto constexpr ConversionFactorHEPToSI() {
@@ -102,10 +115,8 @@ namespace corsika::units::si {
     int constexpr q = -m - t;
     static_assert(q == l + e - 2 * m, "HEP/SI dimension mismatch!");
 
-    using namespace detail;
-    return static_pow<-e>(corsika::units::constants::hBarC) *
-           static_pow<p>(corsika::units::constants::hBar) *
-           static_pow<q>(corsika::units::constants::c);
+    return static_pow<-e>(constants::hBarC) * static_pow<p>(constants::hBar) *
+           static_pow<q>(constants::c);
   }
 
   template <typename DimFrom>
@@ -122,10 +133,8 @@ namespace corsika::units::si {
     int constexpr q = m + t;
     int constexpr e = m - t - l;
 
-    using namespace detail;
-    return static_pow<e>(corsika::units::constants::hBarC) *
-           static_pow<p>(corsika::units::constants::hBar) *
-           static_pow<q>(corsika::units::constants::c);
+    return static_pow<e>(constants::hBarC) * static_pow<p>(constants::hBar) *
+           static_pow<q>(constants::c);
   }
 
   template <typename DimTo, typename DimFrom>
@@ -156,8 +165,18 @@ namespace phys {
       QUANTITY_DEFINE_SCALING_LITERALS(eV, hepenergy_d, 1)
 
       QUANTITY_DEFINE_SCALING_LITERALS(b, corsika::units::si::sigma_d,
-                                       magnitude(corsika::units::constants::barn))
+                                       magnitude(corsika::constants::barn))
 
     } // namespace literals
   }   // namespace units
 } // namespace phys
+
+// import into main \namespace corsika here:
+namespace corsika {
+  using namespace units;
+  using namespace units::si;
+  using namespace phys::units;
+  using namespace phys::units::literals;
+  using namespace phys::units::io;
+  using phys::units::io::operator<<;
+} // namespace corsika
diff --git a/corsika/framework/geometry/BaseVector.hpp b/corsika/framework/geometry/BaseVector.hpp
index 2665e8c676758c30f819aa58727832ccbc99e1dd..3545ec7e14f93203df544b626b6795c734d451b0 100644
--- a/corsika/framework/geometry/BaseVector.hpp
+++ b/corsika/framework/geometry/BaseVector.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/geometry/CoordinateSystem.hpp b/corsika/framework/geometry/CoordinateSystem.hpp
index c58d05281688fed2a8ad8d11b3654d87ea08a64b..901968cf44ed48a7fc7ed89a0c0833e8067f89d2 100644
--- a/corsika/framework/geometry/CoordinateSystem.hpp
+++ b/corsika/framework/geometry/CoordinateSystem.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -28,11 +28,6 @@ namespace corsika {
   template <typename T>
   class Vector;
 
-  /*
-   * FIXME this statement should be scoped.
-   */
-  using corsika::units::si::length_d;
-
   class CoordinateSystem {
 
     CoordinateSystem const* reference = nullptr;
@@ -62,7 +57,7 @@ namespace corsika {
     auto rotate(QuantityVector<TDim> axis, double angle) const;
 
     template <typename TDim>
-    auto translateAndRotate(QuantityVector<phys::units::length_d> translation,
+    auto translateAndRotate(QuantityVector<length_d> translation,
                             QuantityVector<TDim> axis, double angle);
 
     inline CoordinateSystem const* GetReference() const;
diff --git a/corsika/framework/geometry/FourVector.hpp b/corsika/framework/geometry/FourVector.hpp
index 0c3e1b8d48b4182fc9a74e665f4e7428580b8b9d..3223914803e1f4a4339f3439a11d733c658308e3 100644
--- a/corsika/framework/geometry/FourVector.hpp
+++ b/corsika/framework/geometry/FourVector.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -43,8 +43,7 @@ namespace corsika {
     static_assert(
         std::is_same<typename std::decay<TimeType>::type, SpaceType>::value ||
             std::is_same<typename std::decay<TimeType>::type,
-                         decltype(std::declval<SpaceType>() / corsika::units::si::meter *
-                                  corsika::units::si::second)>::value,
+                         decltype(std::declval<SpaceType>() / meter * second)>::value,
         "Units of time-like and space-like coordinates must either be idential "
         "(e.g. GeV) or [E/c]=[p]");
 
diff --git a/corsika/framework/geometry/Helix.hpp b/corsika/framework/geometry/Helix.hpp
index 9e261d5abff7410583cd7eb6ad929af650804507..85e1e92354064b9d5070a0f51fceeaf921d8b967 100644
--- a/corsika/framework/geometry/Helix.hpp
+++ b/corsika/framework/geometry/Helix.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -15,6 +15,8 @@
 
 namespace corsika {
   /*!
+   * \class Helix
+   *
    * A Helix is defined by the cyclotron frequency \f$ \omega_c \f$, the initial
    * Point r0 and
    * the velocity vectors \f$ \vec{v}_{\parallel} \f$ and \f$ \vec{v}_{\perp} \f$
@@ -28,17 +30,17 @@ namespace corsika {
 
   class Helix {
 
-    using VelocityVec = Vector<units::si::SpeedType::dimension_type>;
+    using VelocityVec = Vector<SpeedType::dimension_type> ;
 
     Point const r0;
-    units::si::FrequencyType const omegaC;
+    FrequencyType const omegaC;
     VelocityVec const vPar;
     VelocityVec const vPerp, uPerp;
 
-    corsika::units::si::LengthType const radius;
+    LengthType const radius;
 
   public:
-    Helix(Point const& pR0, units::si::FrequencyType pOmegaC, VelocityVec const& pvPar,
+    Helix(Point const& pR0, FrequencyType pOmegaC, VelocityVec const& pvPar,
           VelocityVec const& pvPerp)
         : r0(pR0)
         , omegaC(pOmegaC)
@@ -47,16 +49,15 @@ namespace corsika {
         , uPerp(vPerp.cross(vPar.normalized()))
         , radius(pvPar.norm() / abs(pOmegaC)) {}
 
-    inline Point GetPosition(units::si::TimeType t) const;
+    inline Point GetPosition(TimeType t) const;
 
-    inline Point PositionFromArclength(units::si::LengthType l) const;
+    inline Point PositionFromArclength(LengthType l) const;
 
-    inline units::si::LengthType GetRadius() const;
+    inline LengthType GetRadius() const;
 
-    inline units::si::LengthType ArcLength(units::si::TimeType t1,
-                                           units::si::TimeType t2) const;
+    inline LengthType ArcLength(TimeType t1, TimeType t2) const;
 
-    inline units::si::TimeType TimeFromArclength(units::si::LengthType l) const;
+    inline TimeType TimeFromArclength(LengthType l) const;
   };
 
 } // namespace corsika
diff --git a/corsika/framework/geometry/Line.hpp b/corsika/framework/geometry/Line.hpp
index d6eaa028b3981c0bd5a7bd0645a86b4e9b405633..6392b4609f82cf74abcb0e9df183666aa9b9085b 100644
--- a/corsika/framework/geometry/Line.hpp
+++ b/corsika/framework/geometry/Line.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -26,7 +26,7 @@ namespace corsika {
 
   class Line {
 
-    using VelocityVec = Vector<units::si::SpeedType::dimension_type>;
+    using VelocityVec = Vector<SpeedType::dimension_type>;
 
     Point const r0;
     VelocityVec const v0;
@@ -36,14 +36,13 @@ namespace corsika {
         : r0(pR0)
         , v0(pV0) {}
 
-    inline Point GetPosition(units::si::TimeType t) const;
+    inline Point GetPosition(TimeType t) const;
 
-    inline Point PositionFromArclength(units::si::LengthType l) const;
+    inline Point PositionFromArclength(LengthType l) const;
 
-    inline units::si::LengthType ArcLength(units::si::TimeType t1,
-                                           units::si::TimeType t2) const;
+    inline LengthType ArcLength(TimeType t1, TimeType t2) const;
 
-    inline units::si::TimeType TimeFromArclength(units::si::LengthType t) const;
+    inline TimeType TimeFromArclength(LengthType t) const;
 
     inline const Point& GetR0() const;
 
diff --git a/corsika/framework/geometry/Plane.hpp b/corsika/framework/geometry/Plane.hpp
index a2a72e42499ae57e94ad934d99bef697523d5794..d66ad195f59589f67fefe060970d30b794785ad7 100644
--- a/corsika/framework/geometry/Plane.hpp
+++ b/corsika/framework/geometry/Plane.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -16,7 +16,7 @@ namespace corsika {
 
   class Plane {
 
-    using DimLessVec = Vector<corsika::units::si::dimensionless_d>;
+    using DimLessVec = Vector<dimensionless_d>;
 
     Point const fCenter;
     DimLessVec const fNormal;
@@ -28,7 +28,7 @@ namespace corsika {
 
     bool IsAbove(Point const& vP) const;
 
-    units::si::LengthType DistanceTo(corsika::Point const& vP) const;
+    LengthType DistanceTo(corsika::Point const& vP) const;
 
     Point const& GetCenter() const;
 
diff --git a/corsika/framework/geometry/Point.hpp b/corsika/framework/geometry/Point.hpp
index 6105fb8b223c76362f5e5ebd0623d642fd9ede8c..0fd1303cd09d48f4413f2f06921aec5fc29af461 100644
--- a/corsika/framework/geometry/Point.hpp
+++ b/corsika/framework/geometry/Point.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -15,10 +15,6 @@
 
 namespace corsika {
 
-  // FIXME: remove aliasing here
-  using corsika::units::si::length_d;
-  using corsika::units::si::LengthType;
-
   /*!
    * A Point represents a point in position space. It is defined by its
    * coordinates with respect to some CoordinateSystem.
diff --git a/corsika/framework/geometry/QuantityVector.hpp b/corsika/framework/geometry/QuantityVector.hpp
index a104ecf654999761790fcfd98e39af276f4d71dd..b363104484446178a7ea1f6c60f74b1adf3fd99e 100644
--- a/corsika/framework/geometry/QuantityVector.hpp
+++ b/corsika/framework/geometry/QuantityVector.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/geometry/RootCoordinateSystem.hpp b/corsika/framework/geometry/RootCoordinateSystem.hpp
index 3a78e16f54c95585e72799d4b7407172c31b8718..64422fa6f5186ce46e60efcc85fb30e67aa521dc 100644
--- a/corsika/framework/geometry/RootCoordinateSystem.hpp
+++ b/corsika/framework/geometry/RootCoordinateSystem.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/geometry/Sphere.hpp b/corsika/framework/geometry/Sphere.hpp
index ecb98f3061bd30d973b21b1d76910029c451bdb0..187f2816cb036b7eade98d8558604b1a3a8e20cf 100644
--- a/corsika/framework/geometry/Sphere.hpp
+++ b/corsika/framework/geometry/Sphere.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -16,10 +16,10 @@ namespace corsika {
 
   class Sphere : public Volume {
     Point const fCenter;
-    units::si::LengthType const fRadius;
+    LengthType const fRadius;
 
   public:
-    Sphere(Point const& pCenter, units::si::LengthType const pRadius)
+    Sphere(Point const& pCenter, LengthType const pRadius)
         : fCenter(pCenter)
         , fRadius(pRadius) {}
 
@@ -28,7 +28,7 @@ namespace corsika {
 
     inline const Point& GetCenter() const;
 
-    inline units::si::LengthType GetRadius() const;
+    inline LengthType GetRadius() const;
   };
 
 } // namespace corsika
diff --git a/corsika/framework/geometry/Trajectory.hpp b/corsika/framework/geometry/Trajectory.hpp
index 7a76a89f32ff6cf4c5eb4e22f7b44147eb55cf74..a8869a952fdf40da466debe302a738ecc58e96c6 100644
--- a/corsika/framework/geometry/Trajectory.hpp
+++ b/corsika/framework/geometry/Trajectory.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -14,93 +14,32 @@
 
 namespace corsika {
 
-  /**
-   * \class LineTrajectory
-   *
-   * A Trajectory is a description of a momvement of an object in
-   * three-dimensional space that describes the trajectory (connection
-   * between two Points in space), as well as the direction of motion
-   * at any given point.
-   *
-   * A Trajectory has a start `0` and an end `1`, where
-   * e.g. GetPosition(0) returns the start point and GetDirection(1)
-   * the direction of motion at the end. Values outside 0...1 are not
-   * defined.
-   *
-   * A Trajectory has a length in [m], GetLength, a duration in [s], GetDuration.
-   *
-   * Note: so far it is assumed that the speed (d|vec{r}|/dt) between
-   * start and end does not change and is constant for the entire
-   * Trajectory.
-   *
-   **/
-
-  class LineTrajectory {
-
-    using VelocityVec = Vector<corsika::units::si::SpeedType::dimension_type>;
+  template <typename T>
+  class Trajectory : public T {
+
+    TimeType fTimeLength;
 
   public:
-    LineTrajectory() = delete;
-    LineTrajectory(const LineTrajectory&) = default;
-    LineTrajectory(LineTrajectory&&) = default;
-    LineTrajectory& operator=(const LineTrajectory&) = delete;
-
-    /**
-     * \param theLine The geometric \sa Line object that represents a straight-line
-     * connection 
-     *
-     * \param timeLength The time duration to traverse the straight trajectory
-     * in units of \sa TimeType
-     */
-    LineTrajectory(Line const& theLine, corsika::units::si::TimeType timeLength)
-        : line_(theLine)
-        , timeLength_(timeLength)
-        , timeStep_(timeLength)
-        , initialVelocity_(theLine.GetVelocity(corsika::units::si::TimeType::zero()))
-        , finalVelocity_(theLine.GetVelocity(timeLength)) {}
-
-    /**
-     * \param theLine The geometric \sa Line object that represents a straight-line
-     * connection 
-     * 
-     * \param timeLength The time duration to traverse the straight trajectory
-     * in units of \sa TimeType 
-     * 
-     * \param timeStep Time duration to folow eventually curved
-     * trajectory in units of \sa TimesType 
-     * 
-     * \param initialV Initial velocity vector at
-     * start of trajectory \param finalV Final velocity vector at start of trajectory
-     */
-    LineTrajectory(
-        Line const& theLine,
-        corsika::units::si::TimeType timeLength, // length of theLine (straight)
-        corsika::units::si::TimeType timeStep,   // length of bend step (curved)
-        const VelocityVec& initialV, const VelocityVec& finalV)
-        : line_(theLine)
-        , timeLength_(timeLength)
-        , timeStep_(timeStep)
-        , initialVelocity_(initialV)
-        , finalVelocity_(finalV) {}
-
-    const Line& GetLine() const { return line_; }
-    Point GetPosition(double u) const { return line_.GetPosition(timeLength_ * u); }
-    VelocityVec GetVelocity(double u) const {
-      return initialVelocity_ * (1 - u) + finalVelocity_ * u;
-    }
-    Vector<corsika::units::si::dimensionless_d> GetDirection(double u) const {
-      return GetVelocity(u).normalized();
-    }
+    using T::ArcLength;
+    using T::GetPosition;
+
+    Trajectory(T const& theT, TimeType timeLength)
+        : T(theT)
+        , fTimeLength(timeLength) {}
+
+    /*Point GetPosition(TimeType t) const {
+      return fTraj.GetPosition(t + fTStart);
+      }*/
 
     Point GetPosition(double u) const;
 
-    corsika::units::si::TimeType GetDuration() const;
+    TimeType GetDuration() const;
 
-    corsika::units::si::LengthType GetLength() const;
+    LengthType GetLength() const;
 
-    corsika::units::si::LengthType GetDistance(corsika::units::si::TimeType t) const;
+    LengthType GetDistance(TimeType t) const;
 
-    void LimitEndTo(corsika::units::si::LengthType limit);
+    void LimitEndTo(LengthType limit);
 
     auto NormalizedDirection() const;
   };
diff --git a/corsika/framework/geometry/Vector.hpp b/corsika/framework/geometry/Vector.hpp
index af8de9afbe107ae3434055093331139ae5c0527d..7ca7d905e8cbf91d7316c58e035e4b54ae4f3093 100644
--- a/corsika/framework/geometry/Vector.hpp
+++ b/corsika/framework/geometry/Vector.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/geometry/Volume.hpp b/corsika/framework/geometry/Volume.hpp
index 069ad7ef8f976d6c8e557c92962f3b3797d5d63b..0b21df8b1749dd2e09eb00c0f0464f5c3e49939c 100644
--- a/corsika/framework/geometry/Volume.hpp
+++ b/corsika/framework/geometry/Volume.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/sequence/BaseProcess.hpp b/corsika/framework/process/BaseProcess.hpp
similarity index 90%
rename from corsika/framework/sequence/BaseProcess.hpp
rename to corsika/framework/process/BaseProcess.hpp
index 41201d3cb195a850c98d219e7248403ea372d909..a8a353c581067467318c97a9747c3ab0e052d3ca 100644
--- a/corsika/framework/sequence/BaseProcess.hpp
+++ b/corsika/framework/process/BaseProcess.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,7 +8,7 @@
 
 #pragma once
 
-#include <corsika/framework/sequence/ProcessReturn.hpp> // for convenience
+#include <corsika/framework/process/ProcessReturn.hpp> // for convenience
 #include <type_traits>
 
 namespace corsika {
diff --git a/corsika/framework/sequence/BoundaryCrossingProcess.hpp b/corsika/framework/process/BoundaryCrossingProcess.hpp
similarity index 89%
rename from corsika/framework/sequence/BoundaryCrossingProcess.hpp
rename to corsika/framework/process/BoundaryCrossingProcess.hpp
index b49e16fddd6df8d99d5896a90c5a2c9c795f2a23..59d2fa043123b652ffba03f8237e0c1f966fde37 100644
--- a/corsika/framework/sequence/BoundaryCrossingProcess.hpp
+++ b/corsika/framework/process/BoundaryCrossingProcess.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,7 +8,7 @@
 
 #pragma once
 
-#include <corsika/framework/sequence/ProcessReturn.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
 #include <corsika/media/Environment.hpp>
 
 namespace corsika {
diff --git a/corsika/framework/sequence/ContinuousProcess.hpp b/corsika/framework/process/ContinuousProcess.hpp
similarity index 74%
rename from corsika/framework/sequence/ContinuousProcess.hpp
rename to corsika/framework/process/ContinuousProcess.hpp
index 68e4a7f82b59565f6b1811481ac4cdf0550bceab..b24bed9b1017adbbc0748d2688a91eb6fcb270ca 100644
--- a/corsika/framework/sequence/ContinuousProcess.hpp
+++ b/corsika/framework/process/ContinuousProcess.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -9,7 +9,7 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp> // for convenience
+#include <corsika/framework/process/ProcessReturn.hpp> // for convenience
 
 namespace corsika {
 
@@ -32,9 +32,9 @@ namespace corsika {
     template <typename TParticle, typename TTrack>
     EProcessReturn DoContinuous(TParticle&, TTrack const&) const;
 
-    // -> enforce TDerived to implement MaxStepLength...
-    template <typename TParticle, typename TTrack>
-    units::si::LengthType MaxStepLength(TParticle const& p, TTrack const& track) const;
+    // -> enforce derived to implement MaxStepLength...
+    template <typename Particle, typename Track>
+    LengthType MaxStepLength(Particle const& p, Track const& track) const;
   };
 
   // overwrite the default trait class, to mark BaseProcess<T> as useful process
diff --git a/corsika/framework/sequence/DecayProcess.hpp b/corsika/framework/process/DecayProcess.hpp
similarity index 69%
rename from corsika/framework/sequence/DecayProcess.hpp
rename to corsika/framework/process/DecayProcess.hpp
index dc6e1704040a06ee94ed059160b5813995e7ae03..84acb4d8c5abcb70287737abc0db1c2f4810a721 100644
--- a/corsika/framework/sequence/DecayProcess.hpp
+++ b/corsika/framework/process/DecayProcess.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,8 +11,7 @@
 #include <type_traits>
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/setup/SetupTrajectory.hpp>
-#include "corsika/framework/sequence/ProcessReturn.hpp" // for convenience
+#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
@@ -35,12 +34,12 @@ namespace corsika {
     template <typename TParticle>
     EProcessReturn DoDecay(TParticle&);
 
-    template <typename TParticle>
-    corsika::units::si::TimeType GetLifetime(const TParticle&);
+    template <typename Particle>
+    TimeType GetLifetime(Particle& p);
 
-    template <typename TParticle>
-    corsika::units::si::InverseTimeType GetInverseLifetime(const TParticle& particle) {
-      return 1. / GetRef().GetLifetime(particle);
+    template <typename Particle>
+    InverseTimeType GetInverseLifetime(Particle& vP) {
+      return 1. / GetRef().GetLifetime(vP);
     }
 
     /*    template <typename TParticle>
diff --git a/corsika/framework/sequence/InteractionProcess.hpp b/corsika/framework/process/InteractionProcess.hpp
similarity index 71%
rename from corsika/framework/sequence/InteractionProcess.hpp
rename to corsika/framework/process/InteractionProcess.hpp
index af79e598cbb8ffc81a142dee9c8f3e9fd158a389..13a0dce1eb560ff0fc82e5fa1666e73abe6e5938 100644
--- a/corsika/framework/sequence/InteractionProcess.hpp
+++ b/corsika/framework/process/InteractionProcess.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,8 +11,7 @@
 #include <type_traits>
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp> // for convenience
-#include <corsika/setup/SetupTrajectory.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
@@ -36,12 +35,11 @@ namespace corsika {
     EProcessReturn DoInteraction(TParticle&);
 
     template <typename TParticle>
-    corsika::units::si::GrammageType GetInteractionLength(const TParticle&);
+    GrammageType GetInteractionLength(TParticle& p);
 
     template <typename TParticle>
-    corsika::units::si::InverseGrammageType GetInverseInteractionLength(
-        const TParticle& particle) {
-      return 1. / GetRef().GetInteractionLength(particle);
+    InverseGrammageType GetInverseInteractionLength(TParticle& p) {
+      return 1. / GetRef().GetInteractionLength(p);
     }
   };
 
diff --git a/corsika/framework/sequence/ProcessReturn.hpp b/corsika/framework/process/ProcessReturn.hpp
similarity index 94%
rename from corsika/framework/sequence/ProcessReturn.hpp
rename to corsika/framework/process/ProcessReturn.hpp
index b86391ebd7908be14d50d9fb5ead7981527e0333..72949ea01358bdc791e605cd8bb7c2f55d526932 100644
--- a/corsika/framework/sequence/ProcessReturn.hpp
+++ b/corsika/framework/process/ProcessReturn.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/sequence/ProcessSequence.hpp b/corsika/framework/process/ProcessSequence.hpp
similarity index 75%
rename from corsika/framework/sequence/ProcessSequence.hpp
rename to corsika/framework/process/ProcessSequence.hpp
index a24bf087097aac47cc9c2cb7b94a22ef7ef0b037..fdc8565e9a646c64aa6d2d7d8ad23d22bb01258f 100644
--- a/corsika/framework/sequence/ProcessSequence.hpp
+++ b/corsika/framework/process/ProcessSequence.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,16 +8,18 @@
 
 #pragma once
 
-#include <cmath>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/BaseProcess.hpp>
-#include <corsika/framework/sequence/BoundaryCrossingProcess.hpp>
-#include <corsika/framework/sequence/ContinuousProcess.hpp>
-#include <corsika/framework/sequence/DecayProcess.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp>
-#include <corsika/framework/sequence/SecondariesProcess.hpp>
-#include <corsika/framework/sequence/StackProcess.hpp>
+
+#include <corsika/framework/process/BaseProcess.hpp>
+#include <corsika/framework/process/BoundaryCrossingProcess.hpp>
+#include <corsika/framework/process/ContinuousProcess.hpp>
+#include <corsika/framework/process/DecayProcess.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
+#include <corsika/framework/process/SecondariesProcess.hpp>
+#include <corsika/framework/process/StackProcess.hpp>
+
+#include <cmath>
 #include <limits>
 #include <type_traits>
 
@@ -97,39 +99,35 @@ namespace corsika {
     EProcessReturn DoStack(TStack& vS);
 
     template <typename TParticle, typename TTrack>
-    corsika::units::si::LengthType MaxStepLength(TParticle& vP, TTrack& vTrack);
+    LengthType MaxStepLength(TParticle& vP, TTrack& vTrack);
     template <typename TParticle>
-    corsika::units::si::GrammageType GetTotalInteractionLength(TParticle& vP);
+    GrammageType GetTotalInteractionLength(TParticle& vP);
 
     template <typename TParticle>
-    inline corsika::units::si::InverseGrammageType GetTotalInverseInteractionLength(
-        TParticle& vP);
+    inline InverseGrammageType GetTotalInverseInteractionLength(TParticle& vP);
 
     template <typename TParticle>
-    inline corsika::units::si::InverseGrammageType GetInverseInteractionLength(
-        TParticle& vP);
+    inline InverseGrammageType GetInverseInteractionLength(TParticle& vP);
 
     template <typename TParticle, typename TSecondaries>
-    EProcessReturn SelectInteraction(
-        TParticle& vP, TSecondaries& vS,
-        [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_select,
-        corsika::units::si::InverseGrammageType& lambda_inv_count);
+    EProcessReturn SelectInteraction(TParticle& vP, TSecondaries& vS,
+                                     [[maybe_unused]] InverseGrammageType lambda_select,
+                                     InverseGrammageType& lambda_inv_count);
 
     template <typename TParticle>
-    corsika::units::si::TimeType GetTotalLifetime(TParticle& p);
+    TimeType GetTotalLifetime(TParticle& p);
 
     template <typename TParticle>
-    corsika::units::si::InverseTimeType GetTotalInverseLifetime(TParticle& p);
+    InverseTimeType GetTotalInverseLifetime(TParticle& p);
 
     template <typename TParticle>
-    corsika::units::si::InverseTimeType GetInverseLifetime(TParticle& p);
+    InverseTimeType GetInverseLifetime(TParticle& p);
 
     // select decay process
     template <typename TParticle, typename TSecondaries>
-    EProcessReturn SelectDecay(
-        TParticle& vP, TSecondaries& vS,
-        [[maybe_unused]] corsika::units::si::InverseTimeType decay_select,
-        corsika::units::si::InverseTimeType& decay_inv_count);
+    EProcessReturn SelectDecay(TParticle& vP, TSecondaries& vS,
+                               [[maybe_unused]] InverseTimeType decay_select,
+                               InverseTimeType& decay_inv_count);
 
     void Init() {
       A.Init();
@@ -173,4 +171,4 @@ namespace corsika {
 
 } // namespace corsika
 
-#include <corsika/detail/framework/sequence/ProcessSequence.inl>
+#include <corsika/detail/framework/process/ProcessSequence.inl>
diff --git a/corsika/framework/sequence/ProcessSignature.hpp b/corsika/framework/process/ProcessSignature.hpp
similarity index 95%
rename from corsika/framework/sequence/ProcessSignature.hpp
rename to corsika/framework/process/ProcessSignature.hpp
index 346e8a33cc2bb3898c5cce5153cac573d4ee7bd0..a7cca793ea6171f9215a64516628ad40b8e0cc64 100644
--- a/corsika/framework/sequence/ProcessSignature.hpp
+++ b/corsika/framework/process/ProcessSignature.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/sequence/SecondariesProcess.hpp b/corsika/framework/process/SecondariesProcess.hpp
similarity index 84%
rename from corsika/framework/sequence/SecondariesProcess.hpp
rename to corsika/framework/process/SecondariesProcess.hpp
index a6a715f67313ccc059cd1550efd5360b5884f790..273d1a730fe2686ff8086f4ae2a0cdcddcd58c18 100644
--- a/corsika/framework/sequence/SecondariesProcess.hpp
+++ b/corsika/framework/process/SecondariesProcess.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -9,8 +9,7 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp> // for convenience
-#include <corsika/setup/SetupTrajectory.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
diff --git a/corsika/framework/sequence/StackProcess.hpp b/corsika/framework/process/StackProcess.hpp
similarity index 88%
rename from corsika/framework/sequence/StackProcess.hpp
rename to corsika/framework/process/StackProcess.hpp
index a94d8f22cb260b3d44a633c8d5795a77daa0ad0d..162bb789b0d4e8fbcee34f71cba6cc43b7438650 100644
--- a/corsika/framework/sequence/StackProcess.hpp
+++ b/corsika/framework/process/StackProcess.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -9,8 +9,7 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/ProcessReturn.hpp> // for convenience
-#include <corsika/setup/SetupTrajectory.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp> // for convenience
 
 namespace corsika {
 
diff --git a/corsika/framework/random/ExponentialDistribution.hpp b/corsika/framework/random/ExponentialDistribution.hpp
index b8433dcb1df3a044b5d6b15a3bd458e4475d8ba1..ae7d89ad8866ad4371ed5bc52695a37f35d7d98d 100644
--- a/corsika/framework/random/ExponentialDistribution.hpp
+++ b/corsika/framework/random/ExponentialDistribution.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/random/RNGManager.hpp b/corsika/framework/random/RNGManager.hpp
index 0c7e11b90d18e2498b8681113d0c9aced03e862f..6e822466ecd3c2b4673d8c84089f09a30d44eddb 100644
--- a/corsika/framework/random/RNGManager.hpp
+++ b/corsika/framework/random/RNGManager.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/random/UniformRealDistribution.hpp b/corsika/framework/random/UniformRealDistribution.hpp
index affc72d756e0aeb813546ef2009b5662b2c5bd9d..666411a52bf87d8c6bb9eb77c4d3c336c0e1c89c 100644
--- a/corsika/framework/random/UniformRealDistribution.hpp
+++ b/corsika/framework/random/UniformRealDistribution.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/stack/CombinedStack.hpp b/corsika/framework/stack/CombinedStack.hpp
index 2751d8d973ce66dfd6594004d4165ee818834c75..10b2f903c6abcd12e6ae07526349e93254b6dd99 100644
--- a/corsika/framework/stack/CombinedStack.hpp
+++ b/corsika/framework/stack/CombinedStack.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,9 +8,10 @@
 
 #pragma once
 
+//#include <corsika/logging/Logging.h>
 #include <corsika/framework/core/ParticleProperties.hpp>
-#include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/stack/Stack.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 
 namespace corsika {
 
@@ -33,36 +34,20 @@ namespace corsika {
    *
    */
   template <template <typename> typename ParticleInterfaceA,
-            template <typename> typename ParticleInterfaceB, typename StackIterator>
-  class CombinedParticleInterface
+            template <typename> class ParticleInterfaceB, typename StackIterator>
+  struct CombinedParticleInterface
       : public ParticleInterfaceB<ParticleInterfaceA<StackIterator>> {
 
-    // FIXME: class has no ctors, assignment operators etc.
-
-    // template<template <typename> typename _PI>
-    // template <typename StackDataType, template <typename> typename ParticleInterface>
-    // template<typename T1, template <typename> typename T2> friend class Stack<T1, T2>;
-
-    using PI_C =
-        CombinedParticleInterface<ParticleInterfaceA, ParticleInterfaceB, StackIterator>;
-    using PI_A = ParticleInterfaceA<StackIterator>;
-    using PI_B = ParticleInterfaceB<ParticleInterfaceA<StackIterator>>;
-
-  protected:
-    using PI_B::GetIndex;     // choose B, A would also work
-    using PI_B::GetStackData; // choose B, A would also work
-
-  public:
     /**
      * @name wrapper for user functions
      * @{
      *
      * In this set of functions we call the user-provide
-     * ParticleInterface SetParticleData(...) methods, either with
+     * ParticleInterface setParticleData(...) methods, either with
      * parent particle reference, or w/o.
      *
      * There is one implicit assumption here: if only one data tuple
-     * is provided for SetParticleData, the data is passed on to
+     * is provided for setParticleData, the data is passed on to
      * ParticleInterfaceA and the ParticleInterfaceB is
      * default-initialized. There are many occasions where this is the
      * desired behaviour, e.g. for thinning etc.
@@ -70,39 +55,103 @@ namespace corsika {
      */
 
     template <typename... Args1>
-    void SetParticleData(const std::tuple<Args1...> vA);
-
+    void setParticleData(const std::tuple<Args1...> vA) {
+    	pi_a_type::setParticleData(vA);
+    	pi_b_type::setParticleData();
+    }
     template <typename... Args1, typename... Args2>
-    void SetParticleData(const std::tuple<Args1...> vA, const std::tuple<Args2...> vB);
+    void setParticleData(const std::tuple<Args1...> vA, const std::tuple<Args2...> vB) {
+    	pi_a_type::setParticleData(vA);
+        pi_b_type::setParticleData(vB);
+    }
 
     template <typename... Args1>
-    void SetParticleData(PI_C& p, const std::tuple<Args1...> vA);
-
+    void setParticleData(pi_a_type& p, const std::tuple<Args1...> vA) {
+      // static_assert(MT<I>::has_not, "error");
+    	pi_a_type::setParticleData(static_cast<pi_a_type&>(p), vA); // original stack
+        pi_b_type::setParticleData(static_cast<pi_b_type&>(p));     // addon stack
+    }
     template <typename... Args1, typename... Args2>
-    void SetParticleData(PI_C& p, const std::tuple<Args1...> vA,
-                         const std::tuple<Args2...> vB);
+    void setParticleData(pi_c_type& p, const std::tuple<Args1...> vA, const std::tuple<Args2...> vB) {
+
+    	pi_a_type::setParticleData(static_cast<pi_a_type&>(p), vA);
+        pi_b_type::setParticleData(static_cast<pi_b_type&>(p), vB);
+    }
     ///@}
 
     std::string as_string() const {
-      return fmt::format("[[{}][{}]]", PI_A::as_string(), PI_B::as_string());
+      return fmt::format("[[{}][{}]]", pi_a_type::as_string(), pi_b_type::as_string());
     }
+
+  private:
+    typedef CombinedParticleInterface<ParticleInterfaceA, ParticleInterfaceB, StackIterator> pi_c_type ;
+    typedef ParticleInterfaceA<StackIterator> pi_a_type;
+    typedef ParticleInterfaceB<ParticleInterfaceA<StackIterator>> pi_b_type;
+
+  protected:
+    using pi_b_type::getIndex;     // choose B, A would also work
+    using pi_b_type::getStackData; // choose B, A would also work
+
   };
 
-  namespace detail {
+  /**
+   * @class CombinedStackImpl
+   *
+   * Memory implementation of a combined data stack.
+   *
+   * The two stack data user objects Stack1Impl and Stack2Impl are
+   * merged into one consistent Stack container object providing
+   * access to the combined number of data entries.
+   */
+  template <typename Stack1Impl, typename Stack2Impl>
+  class CombinedStackImpl : public Stack1Impl, public Stack2Impl {
+
+  public:
+    void clear() {
+      Stack1Impl::clear();
+      Stack2Impl::clear();
+    }
+
+    unsigned int getSize() const { return Stack1Impl::getSize(); }
+    unsigned int getCapacity() const { return Stack1Impl::getCapacity(); }
 
     /**
-     * @class CombinedStackImpl
-     *
-     * Memory implementation of a combined data stack.
-     *
-     * The two stack data user objects Stack1Impl and Stack2Impl are
-     * merged into one consistent Stack container object providing
-     * access to the combined number of data entries.
+     *   Function to copy particle at location i1 in stack to i2
      */
-    template <typename Stack1Impl, typename Stack2Impl>
-    class CombinedStackImpl;
+    void copy(const unsigned int i1, const unsigned int i2) {
+      if (i1 >= getSize() || i2 >= getSize()) {
+        std::ostringstream err;
+        err << "CombinedStack: trying to access data beyond size of stack!";
+        throw std::runtime_error(err.str());
+      }
+      Stack1Impl::copy(i1, i2);
+      Stack2Impl::copy(i1, i2);
+    }
+
+    /**
+     *   Function to copy particle at location i2 in stack to i1
+     */
+    void swap(const unsigned int i1, const unsigned int i2) {
+      if (i1 >= getSize() || i2 >= getSize()) {
+        std::ostringstream err;
+        err << "CombinedStack: trying to access data beyond size of stack!";
+        throw std::runtime_error(err.str());
+      }
+      Stack1Impl::swap(i1, i2);
+      Stack2Impl::swap(i1, i2);
+    }
+
+    void incrementSize() {
+      Stack1Impl::incrementSize();
+      Stack2Impl::incrementSize();
+    }
+
+    void decrementSize() {
+      Stack1Impl::decrementSize();
+      Stack2Impl::decrementSize();
+    }
 
-  } // namespace detail
+  }; // end class CombinedStackImpl
 
   /**
    * Helper template alias `CombinedStack` to construct new combined
@@ -113,9 +162,9 @@ namespace corsika {
    * initialization are forwarded to Stack1Impl (first).
    */
 
-  template <typename Stack1Impl, typename Stack2Impl, template <typename> typename _PI>
-  using CombinedStack = Stack<detail::CombinedStackImpl<Stack1Impl, Stack2Impl>, _PI>;
+  template <typename Stack1Impl, typename Stack2Impl, template <typename> typename _Pi>
+  typedef  Stack<CombinedStackImpl<Stack1Impl, Stack2Impl>, Pi> combined_stack_type;
 
 } // namespace corsika
 
-#include <corsika/detail/framework/stack/CombinedStack.inl>
+//#include <corsika/detail/framework/stack/CombinedStack.inl>
diff --git a/corsika/framework/stack/ParticleBase.hpp b/corsika/framework/stack/ParticleBase.hpp
index 067f54afb90449f0c9208007be118cd212f26bd6..75a4de78bcb91ab88f8f1513aed0914fe7d6515f 100644
--- a/corsika/framework/stack/ParticleBase.hpp
+++ b/corsika/framework/stack/ParticleBase.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,8 +8,6 @@
 
 #pragma once
 
-#include <type_traits>
-
 namespace corsika {
 
   /**
@@ -41,27 +39,34 @@ namespace corsika {
   */
 
   template <typename StackIterator>
-  class ParticleBase {
+  struct ParticleBase {
 
   public:
-    using StackIteratorType = StackIterator;
+
+    typedef StackIterator stack_iterator_type;
+
     ParticleBase() = default;
 
-  private:
-    // those copy constructors and assigments should never be implemented
-    ParticleBase(ParticleBase&) = delete;
-    ParticleBase operator=(ParticleBase&) = delete;
-    ParticleBase(ParticleBase&&) = delete;
-    ParticleBase operator=(ParticleBase&&) = delete;
+     // those copy constructors and assigments should never be implemented
+    ParticleBase(ParticleBase&)       = delete;
+    ParticleBase(ParticleBase&&)      = delete;
     ParticleBase(const ParticleBase&) = delete;
+
+    ParticleBase operator=(ParticleBase&)       = delete;
+    ParticleBase operator=(ParticleBase&&)      = delete;
     ParticleBase operator=(const ParticleBase&) = delete;
 
-  public:
+
     /**
      * Delete this particle on the stack. The corresponding iterator
      * will be invalidated by this operation
      */
-    void Delete() { GetIterator().GetStack().Delete(GetIterator()); }
+    void erase() { this->getIterator().getStack().erase(this->getIterator()); }
+
+    /**
+     * Method to retrieve the status of the Particle. Is it already deleted? Or not.
+     */
+    bool isDeleted() const { return this->getIterator().getStack().isDeleted(this->getIterator()); }
 
     /**
      * Method to retrieve the status of the Particle. Is it already deleted? Or not.
@@ -74,8 +79,9 @@ namespace corsika {
      * function description in the user defined ParticleInterface::AddSecondary(...)
      */
     template <typename... TArgs>
-    StackIterator AddSecondary(const TArgs... args) {
-      return GetStack().AddSecondary(GetIterator(), args...);
+    stack_iterator_type addSecondary(const TArgs... args) {
+
+      return this->getStack().addSecondary(this->getIterator(), args...);
     }
 
     // protected: // todo should [MAY]be proteced, but don't now how to 'friend Stack'
@@ -83,27 +89,43 @@ namespace corsika {
     /**
      * return the corresponding StackIterator for this particle
      */
-    StackIterator& GetIterator() { return static_cast<StackIterator&>(*this); }
-    const StackIterator& GetIterator() const {
-      return static_cast<const StackIterator&>(*this);
+    stack_iterator_type& getIterator() {
+    	return static_cast<stack_iterator_type&>(*this);
+    }
+
+    const stack_iterator_type& getIterator() const {
+      return static_cast<const stack_iterator_type&>(*this);
     }
 
   protected:
     /**
         @name Access to underlying stack fData, these are service
-        function for user classes. User code can only rely on GetIndex
-        and GetStackData to retrieve data
+        function for user classes. User code can only rely on getIndex
+        and getStackData to retrieve data
         @{
     */
-    auto& GetStackData() { return GetIterator().GetStackData(); }
-    const auto& GetStackData() const { return GetIterator().GetStackData(); }
-    auto& GetStack() { return GetIterator().GetStack(); }
-    const auto& GetStack() const { return GetIterator().GetStack(); }
+    auto& getStackData() {
+    	return this->getIterator().getStackData();
+    }
+
+    const auto& getStackData() const {
+    	return this->getIterator().getStackData();
+    }
+
+    auto& getStack() {
+    	return this->getIterator().getStack();
+    }
+
+    const auto& getStack() const {
+    	return this->getIterator().getStack();
+    }
 
     /**
      * return the index number of the underlying iterator object
      */
-    unsigned int GetIndex() const { return GetIterator().GetIndexFromIterator(); }
+    size_t getIndex() const {
+    	return this->getIterator().getIndexFromIterator();
+    }
     ///@}
   };
 
diff --git a/corsika/framework/stack/SecondaryView.hpp b/corsika/framework/stack/SecondaryView.hpp
index 882310589fb997b3745cc26cbb59ab8d4e5eb9be..7986159db6eb81eaddab84dad8ff33ec21228de9 100644
--- a/corsika/framework/stack/SecondaryView.hpp
+++ b/corsika/framework/stack/SecondaryView.hpp
@@ -1,17 +1,17 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
-
 #pragma once
 
 #include <corsika/framework/stack/Stack.hpp>
-#include <corsika/framework/stack/StackIteratorInterface.hpp>
+
+//#include <corsika/logging/Logging.h>
+
 #include <stdexcept>
-#include <type_traits>
 #include <vector>
 
 namespace corsika {
@@ -24,21 +24,21 @@ namespace corsika {
    * @class SecondaryView
    *
    * SecondaryView can only be constructed by giving a valid
-   * Projectile particle, following calls to AddSecondary will
+   * Projectile particle, following calls to addSecondary will
    * populate the original Stack, but will be directly accessible via
    * the SecondaryView, e.g.
 
      This allows to write code like
      \verbatim
-     auto projectileInput = mainStack.GetNextParticle();
-     const unsigned int nMain = mainStack.GetSize();
+     auto projectileInput = mainStack.getNextParticle();
+     const unsigned int nMain = mainStack.getSize();
      SecondaryView<StackData, ParticleInterface> mainStackView(projectileInput);
-     mainStackView.AddSecondary(...data...);
-     mainStackView.AddSecondary(...data...);
-     mainStackView.AddSecondary(...data...);
-     mainStackView.AddSecondary(...data...);
-     assert(mainStackView.GetSize() == 4);
-     assert(mainStack.GetSize() = nMain+4);
+     mainStackView.addSecondary(...data...);
+     mainStackView.addSecondary(...data...);
+     mainStackView.addSecondary(...data...);
+     mainStackView.addSecondary(...data...);
+     assert(mainStackView.getSize() == 4);
+     assert(mainStack.getSize() = nMain+4);
      \endverbatim
 
      All operations possible on a Stack object are also possible on a
@@ -52,49 +52,68 @@ namespace corsika {
      the original stack slot indices. The index of the primary
      projectle particle is also explicitly stored in
      'projectile_index_'. StackIterator indices
-     'i = StackIterator::GetIndex()' are referring to those numbers,
+     'i = StackIterator::getIndex()' are referring to those numbers,
      where 'i==0' refers to the 'projectile_index_', and
-     'StackIterator::GetIndex()>0' to 'indices_[i-1]', see function
-     GetIndexFromIterator.
+     'StackIterator::getIndex()>0' to 'indices_[i-1]', see function
+     getIndexFromIterator.
    */
 
-  template <typename StackDataType, template <typename> typename ParticleInterface,
-            template <class T1, template <class> class T2> class MSecondaryProducer =
-                DefaultSecondaryProducer>
-
+  template <typename StackDataType,
+            template <typename> typename ParticleInterface,
+            template <typename T1, template <class> class T2> class MSecondaryProducer = DefaultSecondaryProducer>
   class SecondaryView : public Stack<StackDataType&, ParticleInterface>,
-                        public MSecondaryProducer<StackDataType, ParticleInterface> {
-    using ViewType = SecondaryView<StackDataType, ParticleInterface, MSecondaryProducer>;
+                        public MSecondaryProducer<StackDataType, ParticleInterface>
+  {
 
-  private:
+	//using ViewType = SecondaryView<StackDataType, ParticleInterface, MSecondaryProducer>;
+    typedef SecondaryView<StackDataType, ParticleInterface, MSecondaryProducer> view_type;
     /**
      * Helper type for inside this class
      */
-    using InnerStackTypeRef = Stack<StackDataType&, ParticleInterface>;
-    using InnerStackTypeRef::getDeleted;
+    //using InnerStackTypeRef = Stack<StackDataType&, ParticleInterface>;
+    typedef Stack<StackDataType&, ParticleInterface> inner_stack_reference_type;
+
+    //using InnerStackTypeValue = Stack<StackDataType, ParticleInterface>;
+    typedef Stack<StackDataType, ParticleInterface>  inner_stack_value_type;
+
+    using inner_stack_reference_type::getDeleted;
 
     /**
      * @name We need this "special" types with non-reference StackData for
      * the constructor of the SecondaryView class
      * @{
      */
-    using InnerStackTypeValue = Stack<StackDataType, ParticleInterface>;
+
 
   public:
-    using StackIteratorValue =
-        StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
-                               ParticleInterface, InnerStackTypeValue>;
-    using ConstStackIteratorValue =
-        ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
-                                    ParticleInterface, InnerStackTypeValue>;
-    /// @}
 
-    using StackIterator =
-        StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
-                               ParticleInterface, ViewType>;
-    using ConstStackIterator =
-        ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
-                                    ParticleInterface, ViewType>;
+//    using StackIteratorValue =
+//        StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+//                               ParticleInterface, InnerStackTypeValue>;
+   typedef  StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+                                   ParticleInterface, inner_stack_value_type> stack_value_iterator;
+
+//    using ConstStackIteratorValue =
+//        ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+//                                    ParticleInterface, inner_stack_value_type>;
+
+   typedef ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+                                       ParticleInterface, inner_stack_value_type> const_stack_value_iterator;
+       /// @}
+
+//    using StackIterator =
+//        StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+//                               ParticleInterface, view_type>;
+
+    typedef  StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+                               ParticleInterface, view_type> stack_view_iterator;
+
+//    using ConstStackIterator =
+//        ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+//                                    ParticleInterface, view_type>;
+
+    typedef ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+                                    ParticleInterface, view_type> const_stack_view_iterator;
 
     /**
      * this is the full type of the declared ParticleInterface: typedef typename
@@ -103,14 +122,14 @@ namespace corsika {
     using ParticleInterfaceType = typename StackIterator::ParticleInterfaceType;
 
     friend class StackIteratorInterface<
-        typename std::remove_reference<StackDataType>::type, ParticleInterface, ViewType>;
+        typename std::remove_reference<StackDataType>::type, ParticleInterface, view_type>;
 
     friend class ConstStackIteratorInterface<
-        typename std::remove_reference<StackDataType>::type, ParticleInterface, ViewType>;
+        typename std::remove_reference<StackDataType>::type, ParticleInterface, view_type>;
 
     friend class ParticleBase<StackIterator>;
 
-  private:
+
     /**
      * This is not accessible, since we don't want to allow creating a
      * new stack.
@@ -119,32 +138,26 @@ namespace corsika {
     SecondaryView(Args... args) = delete;
     SecondaryView() = delete;
 
-  private:
-    InnerStackTypeValue& inner_stack_;
-    unsigned int projectile_index_;
-    std::vector<unsigned int> indices_;
-
-  public:
-    /**
+   /**
        SecondaryView can only be constructed passing it a valid
        StackIterator to another Stack object (here: lvalue)
      **/
-    SecondaryView(StackIteratorValue& particle)
-        : Stack<StackDataType&, ParticleInterface>(particle.GetStackData())
+    SecondaryView(stack_value_iterator& particle)
+        : Stack<StackDataType&, ParticleInterface>(particle.getStackData())
         , MSecondaryProducer<StackDataType, ParticleInterface>{particle}
-        , inner_stack_(particle.GetStack())
-        , projectile_index_(particle.GetIndex()) {
+        , inner_stack_(particle.getStack())
+        , projectile_index_(particle.getIndex()) {
       C8LOG_TRACE("SecondaryView::SecondaryView(particle&)");
     }
     /**
        SecondaryView can only be constructed passing it a valid
        StackIterator to another Stack object (here: rvalue)
      **/
-    SecondaryView(StackIteratorValue&& particle)
-        : Stack<StackDataType&, ParticleInterface>(particle.GetStackData())
+    SecondaryView(stack_value_iterator&& particle)
+        : Stack<StackDataType&, ParticleInterface>(particle.getStackData())
         , MSecondaryProducer<StackDataType, ParticleInterface>{particle}
-        , inner_stack_(particle.GetStack())
-        , projectile_index_(particle.GetIndex()) {
+        , inner_stack_(particle.getStack())
+        , projectile_index_(particle.getIndex()) {
       C8LOG_TRACE("SecondaryView::SecondaryView(particle&&)");
     }
     /**
@@ -153,12 +166,12 @@ namespace corsika {
      * Note, the view generated this way will be equivalent to the orignal view in
      * terms of reference to the underlying data stack. It is not a "view to a view".
      */
-    SecondaryView(ViewType& view, StackIterator& projectile)
-        : Stack<StackDataType&, ParticleInterface>{view.GetStackData()}
-        , MSecondaryProducer<StackDataType, ParticleInterface>{StackIteratorValue{
-              view.inner_stack_, view.GetIndexFromIterator(projectile.GetIndex())}}
+    SecondaryView(view_type& view, stack_view_iterator& projectile)
+        : Stack<StackDataType&, ParticleInterface>{view.getStackData()}
+        , MSecondaryProducer<StackDataType, ParticleInterface>{stack_value_iterator{
+              view.inner_stack_, view.getIndexFromIterator(projectile.getIndex())}}
         , inner_stack_{view.inner_stack_}
-        , projectile_index_{view.GetIndexFromIterator(projectile.GetIndex())} {
+        , projectile_index_{view.getIndexFromIterator(projectile.getIndex())} {
       C8LOG_TRACE("SecondaryView::SecondaryView(view, projectile)");
     }
 
@@ -167,9 +180,9 @@ namespace corsika {
      * SecondaryView is derived from. This projectile should not be
      * used to modify the Stack!
      */
-    StackIteratorValue parent()
-        const { // todo: check if this can't be ConstStackIteratorValue
-      return StackIteratorValue(inner_stack_, projectile_index_);
+    stack_value_iterator parent()
+        const { // todo: check if this can't be Conststack_value_iterator
+      return stack_value_iterator(inner_stack_, projectile_index_);
     }
 
     /**
@@ -177,44 +190,41 @@ namespace corsika {
      * SecondaryView is derived from. This projectile should not be
      * used to modify the Stack!
      */
-    StackIteratorValue asNewParent() const {
-      return StackIteratorValue(inner_stack_, projectile_index_);
+    stack_value_iterator asNewParent() const {
+      return stack_value_iterator(inner_stack_, projectile_index_);
     }
 
     /**
      * This return a projectile of this SecondaryView, which can be
      * used to modify the SecondaryView
      */
-    StackIterator GetProjectile() {
-      // NOTE: 0 is special marker here for PROJECTILE, see GetIndexFromIterator
-      return StackIterator(*this, 0);
+    stack_view_iterator getProjectile() {
+      // NOTE: 0 is special marker here for PROJECTILE, see getIndexFromIterator
+      return stack_view_iterator(*this, 0);
     }
-
-  public:
     /**
      * Method to add a new secondary particle on this SecondaryView
      */
     template <typename... Args>
-    auto AddSecondary(const Args... v);
-
-  protected:
-    /**
-     * Overwrite of Stack::StackIterator
-     *
-     * increase stack size, create new particle at end of stack,
-     * related to parent particle/projectile
-     *
-     * This should only get internally called from a
-     * StackIterator::AddSecondary via ParticleBase
-     */
-    template <typename... Args>
-    auto AddSecondary(StackIterator& proj, const Args... v);
+    stack_view_iterator addSecondary(const Args... v) {
+      C8LOG_TRACE("SecondaryView::addSecondary(Args&&)");
+      stack_view_iterator proj = getProjectile(); // make this const
+      return addSecondary(proj, v...);
+    }
     /**
-     * overwrite Stack::GetSize to return actual number of secondaries
+     * overwrite Stack::getSize to return actual number of secondaries
      */
-    unsigned int getSize() const { return indices_.size(); }
-    unsigned int getEntries() const { return getSize() - getDeleted(); }
-    bool IsEmpty() const { return getEntries() == 0; }
+    unsigned int getSize() const {
+    	return indices_.size();
+    }
+
+    unsigned int getEntries() const {
+    	return getSize() - getDeleted();
+    }
+
+    bool IsEmpty() const {
+    	return getEntries() == 0;
+    }
 
     /**
      * @name These are functions required by std containers and std loops
@@ -223,21 +233,25 @@ namespace corsika {
      * @{
      */
     // NOTE: the "+1" is since "0" is special marker here for PROJECTILE, see
-    // GetIndexFromIterator
-    StackIterator begin() {
+    // getIndexFromIterator
+    stack_view_iterator begin() {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!isDeleted(i)) break;
       }
-      return StackIterator(*this, i + 1);
+      return stack_view_iterator(*this, i + 1);
+    }
+
+    auto end() {
+    	return stack_view_iterator(*this, getSize() + 1);
     }
-    auto end() { return StackIterator(*this, getSize() + 1); }
+
     auto last() {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!isDeleted(getSize() - 1 - i)) break;
       }
-      return StackIterator(*this, getSize() - 1 - i + 1);
+      return stack_view_iterator(*this, getSize() - 1 - i + 1);
     }
 
     auto begin() const {
@@ -245,15 +259,20 @@ namespace corsika {
       for (; i < getSize(); ++i) {
         if (!isDeleted(i)) break;
       }
-      return ConstStackIterator(*this, i + 1);
+
+      return const_stack_view_iterator(*this, i + 1);
     }
-    auto end() const { return ConstStackIterator(*this, getSize() + 1); }
+
+    auto end() const {
+    	return const_stack_view_iterator(*this, getSize() + 1);
+    }
+
     auto last() const {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!isDeleted(getSize() - 1 - i)) break;
       }
-      return ConstStackIterator(*this, getSize() - 1 - i + 1);
+      return const_stack_view_iterator(*this, getSize() - 1 - i + 1);
     }
 
     auto cbegin() const {
@@ -261,36 +280,52 @@ namespace corsika {
       for (; i < getSize(); ++i) {
         if (!isDeleted(i)) break;
       }
-      return ConstStackIterator(*this, i + 1);
+      return const_stack_view_iterator(*this, i + 1);
     }
-    auto cend() const { return ConstStackIterator(*this, getSize()); }
+
+    auto cend() const {
+    	return const_stack_view_iterator(*this, getSize());
+    }
+
     auto clast() const {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!isDeleted(getSize() - 1 - i)) break;
       }
-      return ConstStackIterator(*this, getSize() - 1 - i + 1);
+      return const_stack_view_iterator(*this, getSize() - 1 - i + 1);
+    }
+
+    stack_view_iterator at(unsigned int i) {
+    	return stack_view_iterator(*this, i);
+    }
+
+    const_stack_view_iterator at(unsigned int i) const {
+    	return const_stack_view_iterator(*this, i);
+    }
+
+    stack_view_iterator first() {
+    	return stack_view_iterator{*this, 0};
+    }
+
+    const_stack_view_iterator cfirst() const {
+    	return const_stack_view_iterator{*this, 0};
     }
-    StackIterator at(unsigned int i) { return StackIterator(*this, i); }
-    ConstStackIterator at(unsigned int i) const { return ConstStackIterator(*this, i); }
-    StackIterator first() { return StackIterator{*this, 0}; }
-    ConstStackIterator cfirst() const { return ConstStackIterator{*this, 0}; }
     /// @}
 
-    void Swap(StackIterator a, StackIterator b) {
-      C8LOG_TRACE("View::Swap");
-      inner_stack_.Swap(GetIndexFromIterator(a.GetIndex()),
-                        GetIndexFromIterator(b.GetIndex()));
+    void swap(stack_view_iterator a, stack_view_iterator b) {
+      C8LOG_TRACE("View::swap");
+      inner_stack_.swap(getIndexFromIterator(a.getIndex()),
+                        getIndexFromIterator(b.getIndex()));
     }
-    void Copy(StackIterator a, StackIterator b) {
-      C8LOG_TRACE("View::Copy");
-      inner_stack_.Copy(GetIndexFromIterator(a.GetIndex()),
-                        GetIndexFromIterator(b.GetIndex()));
+    void copy(stack_view_iterator a, stack_view_iterator b) {
+      C8LOG_TRACE("View::copy");
+      inner_stack_.copy(getIndexFromIterator(a.getIndex()),
+                        getIndexFromIterator(b.getIndex()));
     }
-    void Copy(ConstStackIterator a, StackIterator b) {
-      C8LOG_TRACE("View::Copy");
-      inner_stack_.Copy(GetIndexFromIterator(a.GetIndex()),
-                        GetIndexFromIterator(b.GetIndex()));
+    void copy(const_stack_view_iterator a, stack_view_iterator b) {
+      C8LOG_TRACE("View::copy");
+      inner_stack_.copy(getIndexFromIterator(a.getIndex()),
+                        getIndexFromIterator(b.getIndex()));
     }
 
     /**
@@ -305,34 +340,61 @@ namespace corsika {
      * remove the last particle.
      *
      */
-    inline void Delete(StackIterator p);
+    void erase(stack_view_iterator p) {
+      C8LOG_TRACE("SecondaryView::Delete");
+      if (IsEmpty()) { /*error*/
+        throw std::runtime_error("Stack, cannot delete entry since size is zero");
+      }
+      if (isDeleted(p.getIndex() - 1)) { /*error*/
+        throw std::runtime_error("Stack, cannot delete entry since already deleted");
+      }
+      inner_stack_.Delete(getIndexFromIterator(p.getIndex()));
+      inner_stack_reference_type::nDeleted_++; // also count in SecondaryView
+    }
 
     /**
-     * return next particle from stack, need to overwrtie Stack::GetNextParticle to get
+     * return next particle from stack, need to overwrtie Stack::getNextParticle to get
      * right reference
      */
-    inline void Delete(ParticleInterfaceType p);
+    stack_view_iterator getNextParticle() {
+      while (purgeLastIfDeleted()) {}
+      return last();
+    }
+
     /**
      * check if this particle was already deleted
      *
      * need to re-implement for SecondaryView since StackIterator types are a bit
      * different
      */
-    bool isDeleted(const StackIterator& p) const { return isDeleted(p.GetIndex() - 1); }
-    bool isDeleted(const ConstStackIterator& p) const {
-      return isDeleted(p.GetIndex() - 1);
+    bool isDeleted(const stack_view_iterator& p) const {
+    	return isDeleted(p.getIndex() - 1);
+    }
+
+    bool isDeleted(const const_stack_view_iterator& p) const {
+      return isDeleted(p.getIndex() - 1);
     }
     /**
      * delete this particle
      */
-    inline void DeleteLast();
+    bool isDeleted(const ParticleInterfaceType& p) const {
+      return isDeleted(p.getIterator());
+    }
 
     /**
      * Function to ultimatively remove the last entry from the stack,
      * if it was marked as deleted before. If this is not the case,
      * the function will just return false and do nothing.
      */
-    inline StackIterator GetNextParticle() { return last(); }
+    bool purgeLastIfDeleted() {
+      C8LOG_TRACE("SecondaryView::purgeLastIfDeleted");
+      if (!isDeleted(getSize() - 1))
+        return false; // the last particle is not marked for deletion. Do nothing.
+      inner_stack_.purge(getIndexFromIterator(getSize()));
+      inner_stack_reference_type::nDeleted_--;
+      indices_.pop_back();
+      return true;
+    }
 
     /**
      * Function to ultimatively remove all entries from the stack
@@ -342,14 +404,69 @@ namespace corsika {
      * "gaps" in the stack are filled with entries from the back
      * (copied).
      */
-    inline bool IsEmpty() { return GetSize() == 0; }
+    void purge() {
+      unsigned int iStack = 0;
+      unsigned int size = getSize();
+      while (iStack < size) {
+        if (isDeleted(iStack)) {
+          inner_stack_.purge(iStack);
+          indices_.erase(indices_.begin() + iStack);
+        }
+        size = getSize();
+        iStack++;
+      }
+      inner_stack_reference_type::nDeleted_ = 0;
+    }
+
+    std::string as_string() const {
+      std::string str(fmt::format("size {}\n", getSize()));
+      // we make our own begin/end since we want ALL entries
+      std::string new_line = "     ";
+      for (unsigned int iPart = 0; iPart != getSize(); ++iPart) {
+    	  const_stack_view_iterator itPart(*this, iPart);
+        str += fmt::format(
+            "{}{}{}", new_line, itPart.as_string(),
+            (inner_stack_.deleted_[getIndexFromIterator(itPart.getIndex())] ? " [deleted]"
+                                                                            : ""));
+        new_line = "\n     ";
+      }
+      return str;
+    }
 
   protected:
+
+     /**
+      * Overwrite of Stack::StackIterator
+      *
+      * increase stack size, create new particle at end of stack,
+      * related to parent particle/projectile
+      *
+      * This should only get internally called from a
+      * StackIterator::addSecondary via ParticleBase
+      */
+     template <typename... Args>
+     stack_view_iterator addSecondary(stack_view_iterator& proj, const Args... v) {
+       C8LOG_TRACE("SecondaryView::addSecondary(StackIterator&, Args&&)");
+       // make space on stack
+       inner_stack_reference_type::getStackData().IncrementSize();
+       inner_stack_.deleted_.push_back(false);
+       // get current number of secondaries on stack
+       const unsigned int idSec = getSize();
+       // determine index on (inner) stack where new particle will be located
+       const unsigned int index = inner_stack_reference_type::getStackData().getSize() - 1;
+       indices_.push_back(index);
+       // NOTE: "+1" is since "0" is special marker here for PROJECTILE, see
+       // getIndexFromIterator
+       auto sec = stack_view_iterator(*this, idSec + 1, proj, v...);
+       MSecondaryProducer<StackDataType, ParticleInterface>::new_secondary(sec);
+       return sec;
+     }
+
     // forward to inner stack
     // this also checks the allowed bounds of 'i'
     bool isDeleted(unsigned int i) const {
       if (i >= indices_.size()) return false;
-      return inner_stack_.isDeleted(GetIndexFromIterator(i + 1));
+      return inner_stack_.isDeleted(getIndexFromIterator(i + 1));
     }
 
     /**
@@ -357,7 +474,20 @@ namespace corsika {
      * function the conversion form iterator-index to stack-index is
      * performed.
      */
-    inline unsigned int GetIndexFromIterator(const unsigned int vI) const;
+    unsigned int getIndexFromIterator(const unsigned int vI) const {
+      // this is too much: C8LOG_TRACE("SecondaryView::getIndexFromIterator({})={}", vI,
+      // (vI?indices_[vI-1]:projectile_index_));
+      if (vI == 0) return projectile_index_;
+      return indices_[vI - 1];
+    }
+
+  private:
+    inner_stack_value_type& inner_stack_;
+    unsigned int projectile_index_;
+    std::vector<unsigned int> indices_;
+  };
+
+
 
   /**
    * Class to handle the generation of new secondaries. Used as default mix-in for
@@ -394,6 +524,8 @@ namespace corsika {
     DefaultSecondaryProducer(Particle const&) {
       C8LOG_TRACE("DefaultSecondaryProducer::DefaultSecondaryProducer(Particle&)");
     }
+
+
   };
 
   /*
@@ -410,10 +542,11 @@ namespace corsika {
             class MSecondaryProducer = corsika::stack::DefaultSecondaryProducer,
             template <typename> typename MPIType_ = TStack::template MPIType>
   struct MakeView {
-    using type = corsika::SecondaryView<typename S::StackImpl, _PIType>;
+    using type = corsika::stack::SecondaryView<typename TStack::StackImpl, MPIType_, MSecondaryProducer>;
   };
 #endif
 
 } // namespace corsika
 
-#include <corsika/detail/framework/stack/SecondaryView.inl>
+
+//#include <corsika/detail/framework/stack/SecondaryView.inl>
diff --git a/corsika/framework/stack/Stack.hpp b/corsika/framework/stack/Stack.hpp
index 02fe6d178d4a25247c18b7a141ddf4d425f70aca..1d00b2a88fbb4a06848be1f8bd8768b711354783 100644
--- a/corsika/framework/stack/Stack.hpp
+++ b/corsika/framework/stack/Stack.hpp
@@ -8,14 +8,15 @@
 
 #pragma once
 
+//#include <corsika/logging/Logging.h>
 #include <corsika/framework/stack/StackIteratorInterface.hpp>
-// must be after StackIteratorInterface
+#include <corsika/framework/utility/MetaProgramming.hpp>
+
 #include <stdexcept>
 #include <string>
 #include <vector>
-
-#include <corsika/framework/stack/SecondaryView.hpp>
-#include <corsika/framework/utility/MetaProgramming.hpp>
+#include <utility>
+#include <type_traits>
 
 /**
    All classes around management of particles on a stack.
@@ -52,166 +53,183 @@ namespace corsika {
      loops, ranges, etc.
    */
 
-  template <typename TStackData, template <typename> typename MParticleInterface>
+  template <typename StackData, template <typename> typename MParticleInterface>
   class Stack {
-    using StackDataValueType = std::remove_reference_t<TStackData>;
-
-  private:
-    TStackData data_; ///< this in general holds all the data and can be quite big
-    std::vector<bool> deleted_; ///< bit field to flag deleted entries
-  protected:
-    unsigned int nDeleted_ = 0;
 
-  private:
-    Stack(Stack&) = delete; ///< since Stack can be very big, we don't want to copy it
-    Stack& operator=(Stack&) =
-        delete; ///< since Stack can be very big, we don't want to copy it
+    typedef typename std::remove_reference<StackData>::type value_type;
 
   public:
-    /**
-     * if TStackData is a reference member we *HAVE* to initialize
-     * it in the constructor, this is typically needed for SecondaryView
-     */
-    template <typename _ = StackDataType,
-              typename = corsika::enable_if<std::is_reference<_>>>
-    Stack(StackDataType vD)
-        : fData(vD) {}
 
-    /**
-     * This constructor takes any argument and passes it on to the
-     * TStackData user class. If the user did not provide a suited
-     * constructor this will fail with an error message.
-     *
-     * Furthermore, this is disabled with enable_if for SecondaryView
-     * stacks, where the inner data container is always a reference
-     * and cannot be initialized here.
-     */
-    template <typename... Args, typename _ = StackDataType,
-              typename = corsika::disable_if<std::is_reference<_>>>
-    Stack(Args... args)
-        : fData(args...) {}
 
-  public:
-    typedef TStackData
-        StackImpl; ///< this is the type of the user-provided data structure
+    typedef StackData  stack_implementation_type; ///< this is the type of the user-provided data structure
 
     template <typename TSI>
-    using MPIType = MParticleInterface<TSI>;
+    using mpi_type = MParticleInterface<TSI>;
 
     /**
      * Via the StackIteratorInterface and ConstStackIteratorInterface
-     * specialization, the type of the StackIterator
+     * specialization, the type of the stack_iterator_type
      * template class is declared for a particular stack data
      * object. Using CRTP, this also determines the type of
      * MParticleInterface template class simultaneously.
      */
-    using StackIterator =
-        StackIteratorInterface<StackDataValueType, MParticleInterface, Stack>;
-    using ConstStackIterator =
-        ConstStackIteratorInterface<StackDataValueType, MParticleInterface, Stack>;
+    typedef StackIteratorInterface<value_type, MParticleInterface, Stack> stack_iterator_type;
+
+    typedef ConstStackIteratorInterface<value_type, MParticleInterface, Stack> const_stack_iterator_type;
 
     /**
      * this is the full type of the user-declared MParticleInterface
      */
-    using ParticleInterfaceType = typename StackIterator::ParticleInterfaceType;
+    typedef typename stack_iterator_type::ParticleInterfaceType particle_interface_type;
     /**
      * In all programming context, the object to access, copy, and
-     * transport particle data is via the StackIterator
+     * transport particle data is via the stack_iterator_type
      */
-    using ParticleType = StackIterator;
+    typedef stack_iterator_type particle_type;
 
-    // friends are needed since they need access to protected members
-    friend class StackIteratorInterface<StackDataValueType, MParticleInterface, Stack>;
-    friend class ConstStackIteratorInterface<StackDataValueType, MParticleInterface,
-                                             Stack>;
-    template <typename T1, //=TStackData,
-              template <typename>
-              typename M1, //=MParticleInterface,
-                           //             template<typename>typename M2>
-              template <class T2, template <class> class T3> class MSecondaryProducer>
-    friend class SecondaryView; //<TStackData,MParticleInterface,M>; // access for
-                                // SecondaryView
+    //========================
 
-    friend class ParticleBase<StackIterator>;
+    Stack() = default;
+
+    Stack(Stack&) = delete; ///< since Stack can be very big, we don't want to copy it
+
+    Stack& operator=(Stack&) = delete; ///< since Stack can be very big, we don't want to copy it
 
-  public:
     /**
-     * @name Most generic proxy methods for TStackData data_
+     * if StackData is a reference member we *HAVE* to initialize
+     * it in the constructor, this is typically needed for SecondaryView
+     */
+    template <typename UType = StackData,
+    		  typename = typename std::enable_if<std::is_reference<UType>::value>::type >
+    Stack(StackData vD)
+        : data_(vD)
+        , deleted_(std::vector<bool>(data_.getSize(), false))
+        , nDeleted_(0) {}
+
+    /**
+     * This constructor takes any argument and passes it on to the
+     * StackData user class. If the user did not provide a suited
+     * constructor this will fail with an error message.
+     *
+     * Furthermore, this is disabled with enable_if for SecondaryView
+     * stacks, where the inner data container is always a reference
+     * and cannot be initialized here.
+     */
+    template <typename... TArgs, typename UType = StackData,
+              typename = typename std::enable_if< std::is_reference<UType>::value >::type >
+    Stack(TArgs... args)
+        : data_(args...)
+        , deleted_(std::vector<bool>(data_.getSize(), false))
+        , nDeleted_(0) {}
+
+
+
+    /**
+     * @name Most generic proxy methods for StackData data_
      * @{
      */
-    unsigned int GetCapacity() const { return fData.GetCapacity(); }
-    unsigned int GetSize() const { return fData.GetSize(); }
+    unsigned int getCapacity() const {
+    	return data_.getCapacity();
+    }
 
-    template <typename... Args>
-    auto Init(Args... args) {
-      return fData.Init(args...);
+    unsigned int getDeleted() const {
+    	return nDeleted_;
     }
 
-    template <typename... Args>
-    auto Clear(Args... args) {
-      return fData.Clear(args...);
+    unsigned int getEntries() const {
+    	return getSize() - getDeleted();
+    }
+
+    template <typename... TArgs>
+    void clear(TArgs... args) {
+      data_.clear(args...);
+      deleted_ = std::vector<bool>(data_.getSize(), false);
+      nDeleted_ = 0;
     }
     ///@}
 
-  public:
     /**
      * @name These are functions required by std containers and std loops
      * @{
      */
-    StackIterator begin() {
+    stack_iterator_type begin() {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!deleted_[i]) break;
       }
-      return StackIterator(*this, i);
+      return stack_iterator_type(*this, i);
+    }
+
+    stack_iterator_type end() {
+    	return stack_iterator_type(*this, getSize());
     }
-    StackIterator end() { return StackIterator(*this, getSize()); }
-    StackIterator last() {
+
+    stack_iterator_type last() {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!deleted_[getSize() - 1 - i]) break;
       }
-      return StackIterator(*this, getSize() - 1 - i);
+      return stack_iterator_type(*this, getSize() - 1 - i);
     }
 
-    ConstStackIterator begin() const {
+    const_stack_iterator_type begin() const {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!deleted_[i]) break;
       }
-      return ConstStackIterator(*this, i);
+      return const_stack_iterator_type(*this, i);
     }
-    ConstStackIterator end() const { return ConstStackIterator(*this, getSize()); }
-    ConstStackIterator last() const {
+
+    const_stack_iterator_type end() const {
+    	return const_stack_iterator_type(*this, getSize());
+    }
+
+    const_stack_iterator_type last() const {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!deleted_[getSize() - 1 - i]) break;
       }
-      return ConstStackIterator(*this, getSize() - 1 - i);
+      return const_stack_iterator_type(*this, getSize() - 1 - i);
     }
 
-    ConstStackIterator cbegin() const {
+    const_stack_iterator_type cbegin() const {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!deleted_[i]) break;
       }
-      return ConstStackIterator(*this, i);
+      return const_stack_iterator_type(*this, i);
+    }
+
+    const_stack_iterator_type cend() const {
+    	return const_stack_iterator_type(*this, getSize());
     }
-    ConstStackIterator cend() const { return ConstStackIterator(*this, getSize()); }
-    ConstStackIterator clast() const {
+
+    const_stack_iterator_type clast() const {
       unsigned int i = 0;
       for (; i < getSize(); ++i) {
         if (!deleted_[getSize() - 1 - i]) break;
       }
-      return ConstStackIterator(*this, getSize() - 1 - i);
+      return const_stack_iterator_type(*this, getSize() - 1 - i);
+    }
+
+    stack_iterator_type at(unsigned int i) {
+    	return stack_iterator_type(*this, i);
+    }
+
+    const_stack_iterator_type at(unsigned int i) const {
+    	return const_stack_iterator_type(*this, i);
+    }
+
+    stack_iterator_type first() {
+    	return stack_iterator_type{*this, 0};
+    }
+
+    const_stack_iterator_type cfirst() const {
+    	return const_stack_iterator_type{*this, 0};
     }
-    StackIterator at(unsigned int i) { return StackIterator(*this, i); }
-    ConstStackIterator at(unsigned int i) const { return ConstStackIterator(*this, i); }
-    StackIterator first() { return StackIterator{*this, 0}; }
-    ConstStackIterator cfirst() const { return ConstStackIterator{*this, 0}; }
     /// @}
 
-    StackIterator GetNextParticle() {
+    stack_iterator_type getNextParticle() {
       while (purgeLastIfDeleted()) {}
       return last();
     }
@@ -220,91 +238,69 @@ namespace corsika {
      * increase stack size, create new particle at end of stack
      */
     template <typename... TArgs>
-    StackIterator AddParticle(const TArgs... v) {
-      C8LOG_TRACE("Stack::AddParticle");
-      data_.IncrementSize();
+    stack_iterator_type addParticle(const TArgs... v) {
+      //C8LOG_TRACE("Stack::AddParticle");
+      data_.incrementSize();
       deleted_.push_back(false);
-      return StackIterator(*this, getSize() - 1, v...);
+      return stack_iterator_type(*this, getSize() - 1, v...);
     }
 
-  protected:
-    /**
-     * increase stack size, create new particle at end of stack, related to parent
-     * particle/projectile
-     *
-     * This should only get internally called from a
-     * StackIterator::AddSecondary via ParticleBase
-     */
-    template <typename... TArgs>
-    StackIterator AddSecondary(StackIterator& parent, const TArgs... v) {
-      C8LOG_TRACE("Stack::AddSecondary");
-      data_.IncrementSize();
-      deleted_.push_back(false);
-      return StackIterator(*this, getSize() - 1, parent, v...);
+    void swap(stack_iterator_type a, stack_iterator_type b) {
+      //C8LOG_TRACE("Stack::Swap");
+      swap(a.getIndex(), b.getIndex());
     }
 
-  public:
-    void Swap(StackIterator a, StackIterator b) {
-      C8LOG_TRACE("Stack::Swap");
-      Swap(a.GetIndex(), b.GetIndex());
-    }
-    void Copy(StackIterator a, StackIterator b) {
-      C8LOG_TRACE("Stack::Copy");
-      Copy(a.GetIndex(), b.GetIndex());
-    }
-    void Copy(ConstStackIterator a, StackIterator b) {
-      C8LOG_TRACE("Stack::Copy");
-      data_.Copy(a.GetIndex(), b.GetIndex());
-      if (deleted_[b.GetIndex()] && !deleted_[a.GetIndex()]) nDeleted_--;
-      if (!deleted_[b.GetIndex()] && deleted_[a.GetIndex()]) nDeleted_++;
-      deleted_[b.GetIndex()] = deleted_[a.GetIndex()];
+    void copy(stack_iterator_type a, stack_iterator_type b) {
+      //C8LOG_TRACE("Stack::Copy");
+      copy(a.getIndex(), b.getIndex());
     }
 
-  protected:
-    void Swap(unsigned int a, unsigned int b) {
-      C8LOG_TRACE("Stack::Swap(unsigned int)");
-      data_.Swap(a, b);
-      std::swap(deleted_[a], deleted_[b]);
-    }
-    void Copy(unsigned int a, unsigned int b) {
-      C8LOG_TRACE("Stack::Copy");
-      data_.Copy(a, b);
-      if (deleted_[b] && !deleted_[a]) nDeleted_--;
-      if (!deleted_[b] && deleted_[a]) nDeleted_++;
-      deleted_[b] = deleted_[a];
+    void copy(const_stack_iterator_type a, stack_iterator_type b) {
+      //C8LOG_TRACE("Stack::Copy");
+      data_.copy(a.getIndex(), b.getIndex());
+      if (deleted_[b.getIndex()] && !deleted_[a.getIndex()]) nDeleted_--;
+      if (!deleted_[b.getIndex()] && deleted_[a.getIndex()]) nDeleted_++;
+      deleted_[b.getIndex()] = deleted_[a.getIndex()];
     }
 
-    /**
-     * delete this particle
-     */
-  public:
-    void Delete(StackIterator p) {
-      C8LOG_TRACE("Stack::Delete");
-      if (IsEmpty()) { /*error*/
+    void erase(stack_iterator_type p) {
+      //C8LOG_TRACE("Stack::Delete");
+      if (this->isEmpty()) { /*error*/
         throw std::runtime_error("Stack, cannot delete entry since size is zero");
       }
-      if (deleted_[p.GetIndex()]) { /*error*/
+      if (deleted_[p.getIndex()]) { /*error*/
         throw std::runtime_error("Stack, cannot delete entry since already deleted");
       }
-      Delete(p.GetIndex());
+      this->erase(p.getIndex());
     }
     /**
      * delete this particle
      */
-    void Delete(ParticleInterfaceType p) { Delete(p.GetIterator()); }
+    void erase(particle_interface_type p) {
+
+    	this->erase(p.getIterator());
+    }
 
     /**
      * check if there are no further non-deleted particles on stack
      */
-    bool IsEmpty() { return getEntries() == 0; }
+    bool isEmpty() {
+    	return getEntries() == 0;
+    }
 
     /**
      * check if this particle was already deleted
      */
-    bool isDeleted(const StackIterator& p) const { return isDeleted(p.GetIndex()); }
-    bool isDeleted(const ConstStackIterator& p) const { return isDeleted(p.GetIndex()); }
-    bool isDeleted(const ParticleInterfaceType& p) const {
-      return isDeleted(p.GetIterator());
+    bool isDeleted(const stack_iterator_type& p) const {
+    	return isDeleted(p.getIndex());
+    }
+
+    bool isDeleted(const const_stack_iterator_type& p) const {
+    	return isDeleted(p.getIndex());
+    }
+
+    bool isDeleted(const particle_interface_type& p) const {
+      return isDeleted(p.getIterator());
     }
 
     /**
@@ -315,8 +311,8 @@ namespace corsika {
     bool purgeLastIfDeleted() {
       if (!deleted_.back())
         return false; // the last particle is not marked for deletion. Do nothing.
-      C8LOG_TRACE("Stack::purgeLastIfDeleted: yes");
-      data_.DecrementSize();
+      //C8LOG_TRACE("Stack::purgeLastIfDeleted: yes");
+      data_.decrementSize();
       nDeleted_--;
       deleted_.pop_back();
       return true;
@@ -339,14 +335,16 @@ namespace corsika {
         // search for last non-deleted particle on stack
         while (deleted_[iStackBack]) { iStackBack--; }
         // copy entry from iStackBack to iStackFront
-        data_.Copy(iStackBack, iStackFront);
-        data_.DecrementSize();
+        data_.copy(iStackBack, iStackFront);
+        data_.decrementSize();
       }
       deleted_.clear();
       nDeleted_ = 0;
     }
 
-    unsigned int getSize() const { return data_.GetSize(); }
+    unsigned int getSize() const {
+    	return data_.getSize();
+    }
 
     std::string as_string() const {
       std::string str(fmt::format("size {}, entries {}, deleted {} \n", getSize(),
@@ -354,21 +352,50 @@ namespace corsika {
       // we make our own begin/end since we want ALL entries
       std::string new_line = "     ";
       for (unsigned int iPart = 0; iPart != getSize(); ++iPart) {
-        ConstStackIterator itPart(*this, iPart);
+        const_stack_iterator_type itPart(*this, iPart);
         str += fmt::format("{}{}{}", new_line, itPart.as_string(),
-                           (deleted_[itPart.GetIndex()] ? " [deleted]" : ""));
+                           (deleted_[itPart.getIndex()] ? " [deleted]" : ""));
         new_line = "\n     ";
       }
       return str;
     }
 
   protected:
+
+    /**
+     * increase stack size, create new particle at end of stack, related to parent
+     * particle/projectile
+     *
+     * This should only get internally called from a
+     * StackIterator::AddSecondary via ParticleBase
+     */
+    template <typename... TArgs>
+    stack_iterator_type addSecondary(stack_iterator_type& parent, const TArgs... v) {
+      //C8LOG_TRACE("Stack::AddSecondary");
+      data_.incrementSize();
+      deleted_.push_back(false);
+      return stack_iterator_type(*this, getSize() - 1, parent, v...);
+    }
+
+    void swap(unsigned int a, unsigned int b) {
+      //C8LOG_TRACE("Stack::Swap(unsigned int)");
+      data_.swap(a, b);
+      std::swap(deleted_[a], deleted_[b]);
+    }
+    void copy(unsigned int a, unsigned int b) {
+      //C8LOG_TRACE("Stack::Copy");
+      data_.copy(a, b);
+      if (deleted_[b] && !deleted_[a]) nDeleted_--;
+      if (!deleted_[b] && deleted_[a]) nDeleted_++;
+      deleted_[b] = deleted_[a];
+    }
+
     bool isDeleted(unsigned int i) const {
       if (i >= deleted_.size()) return false;
       return deleted_.at(i);
     }
 
-    void Delete(unsigned int i) {
+    void erase(unsigned int i) {
       deleted_[i] = true;
       nDeleted_++;
     }
@@ -382,31 +409,61 @@ namespace corsika {
       // search for last non-deleted particle on stack
       while (deleted_[iStackBack]) { iStackBack--; }
       // copy entry from iStackBack to iStackFront
-      data_.Copy(iStackBack, i);
+      data_.copy(iStackBack, i);
       if (deleted_[i]) nDeleted_--;
       deleted_[i] = deleted_[iStackBack];
-      data_.DecrementSize();
+      data_.decrementSize();
       deleted_.pop_back();
     }
 
     /**
      * Function to perform eventual transformation from
-     * StackIterator::GetIndex() to index in data stored in
-     * TStackData data_. By default (and in almost all cases) this
+     * StackIterator::getIndex() to index in data stored in
+     * StackData data_. By default (and in almost all cases) this
      * should just be identiy. See class SecondaryView for an alternative implementation.
      */
-    unsigned int GetIndexFromIterator(const unsigned int vI) const {
-      // this is too much: C8LOG_TRACE("Stack::GetIndexFromIterator({})={}", vI, vI);
+    unsigned int getIndexFromIterator(const unsigned int vI) const {
+      // this is too much: //C8LOG_TRACE("Stack::getIndexFromIterator({})={}", vI, vI);
       return vI;
     }
 
     /**
-     * @name Return reference to TStackData object data_ for data access
+     * @name Return reference to StackData object data_ for data access
      * @{
      */
-    StackDataValueType& GetStackData() { return data_; }
-    const StackDataValueType& GetStackData() const { return data_; }
+    value_type& getStackData() {
+    	return data_;
+    }
+
+    const value_type& getStackData() const {
+    	return data_;
+    }
     ///@}
+    ///
+
+    ///
+    friend class StackIteratorInterface<value_type, MParticleInterface, Stack>;
+    friend class ConstStackIteratorInterface<value_type, MParticleInterface,
+                                             Stack>;
+    template <typename T1, //=StackData,
+              template <typename>
+              typename M1, //=MParticleInterface,
+                           //             template<typename>typename M2>
+              template <class T2, template <class> class T3> class MSecondaryProducer>
+    friend class SecondaryView; //<StackData,MParticleInterface,M>; // access for
+                                // SecondaryView
+
+    friend class ParticleBase<stack_iterator_type>;
+
+  protected:
+
+    unsigned int nDeleted_ = 0;
+
+  private:
+
+    StackData data_; ///< this in general holds all the data and can be quite big
+    std::vector<bool> deleted_; ///< bit field to flag deleted entries
+
   };
 
 } // namespace corsika
diff --git a/corsika/framework/stack/StackIteratorInterface.hpp b/corsika/framework/stack/StackIteratorInterface.hpp
index 490f0857169f8c041f5b50837018c4c8fe5de799..7d3c7a4f3c49345fd77d4f5ed4c5cf94d03c8185 100644
--- a/corsika/framework/stack/StackIteratorInterface.hpp
+++ b/corsika/framework/stack/StackIteratorInterface.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/utility/Bit.hpp b/corsika/framework/utility/Bit.hpp
index ba3fe2b00e7c379ad238ece979836521311560bc..6d9d42c7a09b25bc10b9bea1107f25fd700e61bb 100644
--- a/corsika/framework/utility/Bit.hpp
+++ b/corsika/framework/utility/Bit.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/utility/COMBoost.hpp b/corsika/framework/utility/COMBoost.hpp
index e32143c4b9be6719f92bf0a3b85c302bfc81ff33..96823d123fb6fb2f9c5ec0c44415dab9ec277fbd 100644
--- a/corsika/framework/utility/COMBoost.hpp
+++ b/corsika/framework/utility/COMBoost.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -31,10 +29,9 @@ namespace corsika {
 
   public:
     //! construct a COMBoost given four-vector of prjectile and mass of target
-    COMBoost(const corsika::FourVector<
-                 corsika::units::si::HEPEnergyType,
-                 corsika::Vector<corsika::units::si::hepmomentum_d>>& Pprojectile,
-             const corsika::units::si::HEPEnergyType massTarget);
+    COMBoost(const corsika::FourVector<HEPEnergyType, corsika::Vector<hepmomentum_d>>&
+                 Pprojectile,
+             const HEPEnergyType massTarget);
 
     inline auto const& GetRotationMatrix() const;
 
diff --git a/corsika/framework/utility/CorsikaFenv.hpp b/corsika/framework/utility/CorsikaFenv.hpp
index 02614eceddce18d0fa94ca1a7d964386471c5eea..dab33fb46d9b6734918869e7b9e28a217ece2346 100644
--- a/corsika/framework/utility/CorsikaFenv.hpp
+++ b/corsika/framework/utility/CorsikaFenv.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/utility/MetaProgramming.hpp b/corsika/framework/utility/MetaProgramming.hpp
index d635991ec0e69ef33e1772d8d257de0ca46024e0..7d6097be1f3efee632e3ccdb3a27b45bba9fd4db 100644
--- a/corsika/framework/utility/MetaProgramming.hpp
+++ b/corsika/framework/utility/MetaProgramming.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/framework/utility/Singleton.hpp b/corsika/framework/utility/Singleton.hpp
index 04665157e822ad7b10c6729ff6e957fb1441878f..7c81cd3050a4c30c0b076bc73dcb68aad8049946 100644
--- a/corsika/framework/utility/Singleton.hpp
+++ b/corsika/framework/utility/Singleton.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/media/BaseExponential.hpp b/corsika/media/BaseExponential.hpp
index 87263d3ccc75a565845542d8d6225d2a13eadd32..577629db28f8fefc1e9d0c3e6f7ab3ddd35e218d 100644
--- a/corsika/media/BaseExponential.hpp
+++ b/corsika/media/BaseExponential.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -26,17 +26,16 @@ namespace corsika {
   class BaseExponential {
 
   public:
-    BaseExponential(Point const& vP0, units::si::MassDensityType vRho,
-                    units::si::LengthType vLambda)
+    BaseExponential(Point const& vP0, MassDensityType vRho, LengthType vLambda)
         : fRho0(vRho)
         , fLambda(vLambda)
         , fInvLambda(1 / vLambda)
         , fP0(vP0) {}
 
   protected:
-    units::si::MassDensityType const fRho0;
-    units::si::LengthType const fLambda;
-    units::si::InverseLengthType const fInvLambda;
+    MassDensityType const fRho0;
+    LengthType const fLambda;
+    InverseLengthType const fInvLambda;
     Point const fP0;
 
     auto const& GetImplementation() const;
@@ -55,9 +54,8 @@ namespace corsika {
      * \f]
      */
     // clang-format on
-    units::si::GrammageType IntegratedGrammage(
-        Trajectory<Line> const& vLine, units::si::LengthType vL,
-        Vector<units::si::dimensionless_d> const& vAxis) const;
+    GrammageType IntegratedGrammage(Trajectory<Line> const& vLine, LengthType vL,
+                                    Vector<dimensionless_d> const& vAxis) const;
 
     // clang-format off
     /**
@@ -77,9 +75,9 @@ namespace corsika {
      * \f]
      */
     // clang-format on
-    units::si::LengthType ArclengthFromGrammage(
-        Trajectory<Line> const& vLine, units::si::GrammageType vGrammage,
-        Vector<units::si::dimensionless_d> const& vAxis) const;
+    LengthType ArclengthFromGrammage(Trajectory<Line> const& vLine,
+                                     GrammageType vGrammage,
+                                     Vector<dimensionless_d> const& vAxis) const;
   };
 
 } // namespace corsika
diff --git a/corsika/media/DensityFunction.hpp b/corsika/media/DensityFunction.hpp
index ec2e4e9025ae67f1ffdbcc2175abe87c4ac886ac..8daf12dfa318d20eb24e5e33e73ba4246e0a7fd9 100644
--- a/corsika/media/DensityFunction.hpp
+++ b/corsika/media/DensityFunction.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -27,9 +27,7 @@ namespace corsika {
     DensityFunction(TDerivableRho rho)
         : fRho(rho) {}
 
-    corsika::units::si::MassDensityType EvaluateAt(corsika::Point const& p) const {
-      return fRho(p);
-    }
+    MassDensityType EvaluateAt(corsika::Point const& p) const { return fRho(p); }
   };
 
 } // namespace corsika
diff --git a/corsika/media/Environment.hpp b/corsika/media/Environment.hpp
index 6f30f2898e05f4c64446d9f15b0127a5a0d1c561..4a241d886435786d4ec288d448556b45f87037b4 100644
--- a/corsika/media/Environment.hpp
+++ b/corsika/media/Environment.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/media/FlatExponential.hpp b/corsika/media/FlatExponential.hpp
index 6e32918f89d720b1bac0f010fa0d39047ef19a19..c0757dfc1873170e2e8efd2f0316d4ce67996f9a 100644
--- a/corsika/media/FlatExponential.hpp
+++ b/corsika/media/FlatExponential.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -20,28 +20,28 @@ namespace corsika {
 
   template <class T>
   class FlatExponential : public BaseExponential<FlatExponential<T>>, public T {
-    Vector<units::si::dimensionless_d> const fAxis;
+    Vector<dimensionless_d> const fAxis;
     NuclearComposition const fNuclComp;
 
     using Base = BaseExponential<FlatExponential<T>>;
 
   public:
-    FlatExponential(Point const& vP0, Vector<units::si::dimensionless_d> const& vAxis,
-                    units::si::MassDensityType vRho, units::si::LengthType vLambda,
+    FlatExponential(Point const& vP0, Vector<dimensionless_d> const& vAxis,
+                    MassDensityType vRho, LengthType vLambda,
                     NuclearComposition vNuclComp)
         : Base(vP0, vRho, vLambda)
         , fAxis(vAxis)
         , fNuclComp(vNuclComp) {}
 
-    units::si::MassDensityType GetMassDensity(Point const& vP) const override;
+    MassDensityType GetMassDensity(Point const& vP) const override;
 
     NuclearComposition const& GetNuclearComposition() const override;
 
-    units::si::GrammageType IntegratedGrammage(Trajectory<Line> const& vLine,
-                                               units::si::LengthType vTo) const override;
+    GrammageType IntegratedGrammage(Trajectory<Line> const& vLine,
+                                    LengthType vTo) const override;
 
-    units::si::LengthType ArclengthFromGrammage(
-        Trajectory<Line> const& vLine, units::si::GrammageType vGrammage) const override;
+    LengthType ArclengthFromGrammage(Trajectory<Line> const& vLine,
+                                     GrammageType vGrammage) const override;
   };
 
 } // namespace corsika
diff --git a/corsika/media/HomogeneousMedium.hpp b/corsika/media/HomogeneousMedium.hpp
index 213cac197f6f0a83f62c645213937d7af256cf58..81101825ac559bf7b4923827d16f7c4818f22b86 100644
--- a/corsika/media/HomogeneousMedium.hpp
+++ b/corsika/media/HomogeneousMedium.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -28,32 +28,27 @@ namespace corsika {
 
   template <class T>
   class HomogeneousMedium : public T {
-    corsika::units::si::MassDensityType const fDensity;
+    MassDensityType const fDensity;
     NuclearComposition const fNuclComp;
 
   public:
-    HomogeneousMedium(corsika::units::si::MassDensityType pDensity,
-                      NuclearComposition pNuclComp)
+    HomogeneousMedium(MassDensityType pDensity, NuclearComposition pNuclComp)
         : fDensity(pDensity)
         , fNuclComp(pNuclComp) {}
 
-    corsika::units::si::MassDensityType GetMassDensity(
-        corsika::Point const&) const override {
+    MassDensityType GetMassDensity(corsika::Point const&) const override {
       return fDensity;
     }
 
     NuclearComposition const& GetNuclearComposition() const override { return fNuclComp; }
 
-    corsika::units::si::GrammageType IntegratedGrammage(
-        corsika::Trajectory<corsika::Line> const&,
-        corsika::units::si::LengthType pTo) const override {
-      using namespace corsika::units::si;
+    GrammageType IntegratedGrammage(corsika::Trajectory<corsika::Line> const&,
+                                    LengthType pTo) const override {
       return pTo * fDensity;
     }
 
-    corsika::units::si::LengthType ArclengthFromGrammage(
-        corsika::Trajectory<corsika::Line> const&,
-        corsika::units::si::GrammageType pGrammage) const override {
+    LengthType ArclengthFromGrammage(corsika::Trajectory<corsika::Line> const&,
+                                     GrammageType pGrammage) const override {
       return pGrammage / fDensity;
     }
   };
diff --git a/corsika/media/IMediumModel.hpp b/corsika/media/IMediumModel.hpp
index e45928c98f716fbeb71eefe19b7c25676c103cec..538657cb6952a27ce4ff9e0d1ae89ac4ba8ab1fb 100644
--- a/corsika/media/IMediumModel.hpp
+++ b/corsika/media/IMediumModel.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -21,18 +21,15 @@ namespace corsika {
   public:
     virtual ~IMediumModel() = default; // LCOV_EXCL_LINE
 
-    virtual corsika::units::si::MassDensityType GetMassDensity(
-        corsika::Point const&) const = 0;
+    virtual MassDensityType GetMassDensity(Point const&) const = 0;
 
     // todo: think about the mixin inheritance of the trajectory vs the BaseTrajectory
     // approach; for now, only lines are supported
-    virtual corsika::units::si::GrammageType IntegratedGrammage(
-        corsika::Trajectory<corsika::Line> const&,
-        corsika::units::si::LengthType) const = 0;
+    virtual GrammageType IntegratedGrammage(Trajectory<Line> const&,
+                                            LengthType) const = 0;
 
-    virtual corsika::units::si::LengthType ArclengthFromGrammage(
-        corsika::Trajectory<corsika::Line> const&,
-        corsika::units::si::GrammageType) const = 0;
+    virtual LengthType ArclengthFromGrammage(Trajectory<Line> const&,
+                                             GrammageType) const = 0;
 
     virtual NuclearComposition const& GetNuclearComposition() const = 0;
   };
diff --git a/corsika/media/InhomogeneousMedium.hpp b/corsika/media/InhomogeneousMedium.hpp
index f0c5aeb827cb0bf9f05a31fee76146d82bde9626..5df9a04bb43f6f8c7aee85fd8c378eea22e8e750 100644
--- a/corsika/media/InhomogeneousMedium.hpp
+++ b/corsika/media/InhomogeneousMedium.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -37,22 +37,19 @@ namespace corsika {
         : fNuclComp(pNuclComp)
         , fDensityFunction(rhoArgs...) {}
 
-    corsika::units::si::MassDensityType GetMassDensity(
-        corsika::Point const& p) const override {
+    MassDensityType GetMassDensity(Point const& p) const override {
       return fDensityFunction.EvaluateAt(p);
     }
 
     NuclearComposition const& GetNuclearComposition() const override { return fNuclComp; }
 
-    corsika::units::si::GrammageType IntegratedGrammage(
-        corsika::Trajectory<corsika::Line> const& pLine,
-        corsika::units::si::LengthType pTo) const override {
+    GrammageType IntegratedGrammage(Trajectory<Line> const& pLine,
+                                    LengthType pTo) const override {
       return fDensityFunction.IntegrateGrammage(pLine, pTo);
     }
 
-    corsika::units::si::LengthType ArclengthFromGrammage(
-        corsika::Trajectory<corsika::Line> const& pLine,
-        corsika::units::si::GrammageType pGrammage) const override {
+    LengthType ArclengthFromGrammage(Trajectory<Line> const& pLine,
+                                     GrammageType pGrammage) const override {
       return fDensityFunction.ArclengthFromGrammage(pLine, pGrammage);
     }
   };
diff --git a/corsika/media/LayeredSphericalAtmosphereBuilder.hpp b/corsika/media/LayeredSphericalAtmosphereBuilder.hpp
index 196e0ecaa24a69692a3e8801c1569e24e1c06b37..5984913ec6d6ddec046a96d2b859c7e015e7511e 100644
--- a/corsika/media/LayeredSphericalAtmosphereBuilder.hpp
+++ b/corsika/media/LayeredSphericalAtmosphereBuilder.hpp
@@ -26,127 +26,29 @@ namespace corsika {
   class LayeredSphericalAtmosphereBuilder {
     std::unique_ptr<NuclearComposition> composition_;
     Point center_;
-    units::si::LengthType previousRadius_{units::si::LengthType::zero()};
-    units::si::LengthType earthRadius_;
-    std::tuple<TModelArgs...> const additionalModelArgs_;
+    LengthType previousRadius_{LengthType::zero()};
+    LengthType seaLevel_;
 
     std::stack<VolumeTreeNode<IMediumModel>::VTNUPtr> layers_; // innermost layer first
 
-    void checkRadius(units::si::LengthType r) const {
-      if (r <= previousRadius_) {
-        throw std::runtime_error("radius must be greater than previous");
-      }
-    }
+    void checkRadius(LengthType) const;
 
   public:
-    static auto constexpr earthRadius = 6'371'000 * units::si::meter;
+    static auto constexpr earthRadius = 6'371'000 * meter;
 
     LayeredSphericalAtmosphereBuilder(corsika::Point center,
-                                      units::si::LengthType seaLevel = earthRadius)
+                                      LengthType seaLevel = earthRadius)
         : center_(center)
         , earthRadius_(earthRadius)
         , additionalModelArgs_{args...} {}
 
-  public:
-    void setNuclearComposition(NuclearComposition composition) {
-      composition_ = std::make_unique<NuclearComposition>(composition);
-    }
-
-    void addExponentialLayer(units::si::GrammageType b, units::si::LengthType c,
-                             units::si::LengthType upperBoundary) {
-      using namespace units::si;
-
-      auto const radius = earthRadius_ + upperBoundary;
-      checkRadius(radius);
-      previousRadius_ = radius;
-
-      auto node = std::make_unique<VolumeTreeNode<TMediumInterface>>(
-          std::make_unique<geometry::Sphere>(center_, radius));
-
-      auto const rho0 = b / c;
-      std::cout << "rho0 = " << rho0 << ", c = " << c << std::endl;
-
-      if constexpr (detail::has_extra_models<TMediumModelExtra>::value) {
-        // helper lambda in which the last 5 arguments to make_shared<...> are bound
-        auto lastBound = [&](auto... argPack) {
-          return std::make_shared<
-              TMediumModelExtra<environment::SlidingPlanarExponential<TMediumInterface>>>(
-              argPack..., center_, rho0, -c, *composition_, earthRadius_);
-        };
-
-        // now unpack the additional arguments
-        auto model = std::apply(lastBound, additionalModelArgs_);
-        node->SetModelProperties(std::move(model));
-      } else {
-        node->template SetModelProperties<SlidingPlanarExponential<TMediumInterface>>(
-            center_, rho0, -c, *composition_, earthRadius_);
-      }
-
-      layers_.push(std::move(node));
-    }
-
-    void addLinearLayer(units::si::LengthType c, units::si::LengthType upperBoundary) {
-      using namespace units::si;
-
-      auto const radius = earthRadius_ + upperBoundary;
-      checkRadius(radius);
-      previousRadius_ = radius;
-
-      auto node = std::make_unique<VolumeTreeNode<TMediumInterface>>(
-          std::make_unique<geometry::Sphere>(center_, radius));
-
-      units::si::GrammageType constexpr b = 1 * 1_g / (1_cm * 1_cm);
-      auto const rho0 = b / c;
-
-      std::cout << "rho0 = " << rho0;
-
-      if constexpr (detail::has_extra_models<TMediumModelExtra>::value) {
-        // helper lambda in which the last 2 arguments to make_shared<...> are bound
-        auto lastBound = [&](auto... argPack) {
-          return std::make_shared<
-              TMediumModelExtra<environment::HomogeneousMedium<TMediumInterface>>>(
-              argPack..., rho0, *composition_);
-        };
-
-        // now unpack the additional arguments
-        auto model = std::apply(lastBound, additionalModelArgs_);
-
-        node->SetModelProperties(std::move(model));
-      } else {
-        node->template SetModelProperties<
-            environment::HomogeneousMedium<TMediumInterface>>(rho0, *composition_);
-      }
-
-      layers_.push(std::move(node));
-    }
-
-    int size() const { return layers_.size(); }
-
-    void assemble(Environment<TMediumInterface>& env) {
-      auto& universe = env.GetUniverse();
-      auto* outmost = universe.get();
-
-      while (!layers_.empty()) {
-        auto l = std::move(layers_.top());
-        auto* tmp = l.get();
-        outmost->AddChild(std::move(l));
-        layers_.pop();
-        outmost = tmp;
-      }
-    }
-
-    Environment<TMediumInterface> assemble() {
-      Environment<TMediumInterface> env;
-      assemble(env);
-      return env;
-    }
-
-    /**
-     * Get the current Earth radius.
-     */
-    units::si::LengthType getEarthRadius() const { return earthRadius_; }
-
-  }; // end class LayeredSphericalAtmosphereBuilder
+    void setNuclearComposition(NuclearComposition);
+
+    void addExponentialLayer(GrammageType, LengthType, LengthType);
+
+    auto size() const { return layers_.size(); }
+
+    void addLinearLayer(LengthType, LengthType);
 
     void assemble(Environment<IMediumModel>&);
 
diff --git a/corsika/media/LinearApproximationIntegrator.hpp b/corsika/media/LinearApproximationIntegrator.hpp
index f550b846d86bd2d667b4fbf2ffc0a79ecc33f151..ccacc9d601fdda516627fecbd6249c7fff55dc6c 100644
--- a/corsika/media/LinearApproximationIntegrator.hpp
+++ b/corsika/media/LinearApproximationIntegrator.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -22,10 +22,10 @@ namespace corsika {
 
   public:
     inline auto IntegrateGrammage(corsika::Trajectory<corsika::Line> const& line,
-                                  corsika::units::si::LengthType length) const;
+                                  LengthType length) const;
 
     inline auto ArclengthFromGrammage(corsika::Trajectory<corsika::Line> const& line,
-                                      corsika::units::si::GrammageType grammage) const;
+                                      GrammageType grammage) const;
 
     inline auto MaximumLength(corsika::Trajectory<corsika::Line> const& line,
                               [[maybe_unused]] double relError) const;
diff --git a/corsika/media/NameModel.hpp b/corsika/media/NameModel.hpp
index 5963ed937a093e6cfb049440af420dc0c81cff02..e841991d5d9e86062bee96350d3398916c72b872 100644
--- a/corsika/media/NameModel.hpp
+++ b/corsika/media/NameModel.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/media/NuclearComposition.hpp b/corsika/media/NuclearComposition.hpp
index 654e8f13a97c7f4105609c778c3d73d7269862eb..94eef28088dad629805e71e4e4723e963a90d7c2 100644
--- a/corsika/media/NuclearComposition.hpp
+++ b/corsika/media/NuclearComposition.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -75,8 +75,7 @@ namespace corsika {
                 if (IsNucleus(compID)) {
                   return GetNucleusA(compID) * fraction;
                 } else {
-                  return GetMass(compID) /
-                         units::si::ConvertSIToHEP(units::constants::u) * fraction;
+                  return GetMass(compID) / ConvertSIToHEP(constants::u) * fraction;
                 }
               })) {
       assert(pComponents.size() == pFractions.size());
@@ -116,10 +115,8 @@ namespace corsika {
     auto const GetAverageMassNumber() const { return fAvgMassNumber; }
 
     template <class TRNG>
-    corsika::Code SampleTarget(
-        std::vector<corsika::units::si::CrossSectionType> const& sigma,
-        TRNG& randomStream) const {
-      using namespace corsika::units::si;
+    corsika::Code SampleTarget(std::vector<CrossSectionType> const& sigma,
+                               TRNG& randomStream) const {
 
       assert(sigma.size() == fNumberFractions.size());
 
diff --git a/corsika/media/SlidingPlanarExponential.hpp b/corsika/media/SlidingPlanarExponential.hpp
index 6cbab115714ff65c01fbaa63f768e018500d8705..c34949722beb98df496a7b5227ef32753118d2e6 100644
--- a/corsika/media/SlidingPlanarExponential.hpp
+++ b/corsika/media/SlidingPlanarExponential.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -24,30 +24,29 @@ namespace corsika {
                                    public T {
 
     NuclearComposition const nuclComp_;
-    units::si::LengthType const referenceHeight_;
+    LengthType const referenceHeight_;
 
     using Base = BaseExponential<SlidingPlanarExponential<T>>;
 
   public:
-    SlidingPlanarExponential(
-        Point const& p0, units::si::MassDensityType rho0, units::si::LengthType lambda,
-        NuclearComposition nuclComp,
-        units::si::LengthType referenceHeight = units::si::LengthType::zero())
+    SlidingPlanarExponential(Point const& p0, MassDensityType rho0, LengthType lambda,
+                             NuclearComposition nuclComp,
+                             LengthType referenceHeight = LengthType::zero())
         : Base(p0, rho0, lambda)
         , nuclComp_(nuclComp)
         , referenceHeight_(referenceHeight) {}
 
-    inline units::si::MassDensityType GetMassDensity(Point const& p) const override;
+    inline MassDensityType GetMassDensity(Point const& p) const override;
 
     inline NuclearComposition const& GetNuclearComposition() const override {
       return nuclComp_;
     }
 
-    inline units::si::GrammageType IntegratedGrammage(
-        Trajectory<Line> const& line, units::si::LengthType l) const override;
+    inline GrammageType IntegratedGrammage(Trajectory<Line> const& line,
+                                           LengthType l) const override;
 
-    inline units::si::LengthType ArclengthFromGrammage(
-        Trajectory<Line> const& line, units::si::GrammageType grammage) const override;
+    inline LengthType ArclengthFromGrammage(Trajectory<Line> const& line,
+                                            GrammageType grammage) const override;
   };
 
 } // namespace corsika
diff --git a/corsika/media/Universe.hpp b/corsika/media/Universe.hpp
index 112dfadc2aed02bf29bec1aa89c483a97cb839ba..753526edd19fc43e25dd880c802f035cac1fe865 100644
--- a/corsika/media/Universe.hpp
+++ b/corsika/media/Universe.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/media/VolumeTreeNode.hpp b/corsika/media/VolumeTreeNode.hpp
index a69cd6fb3a6475928c8ff4aeb656382d449e0312..6d1aff6158b53e4a3dcb1e0fbc02ded8a3f20830 100644
--- a/corsika/media/VolumeTreeNode.hpp
+++ b/corsika/media/VolumeTreeNode.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/modules/BetheBlochPDG.hpp b/corsika/modules/BetheBlochPDG.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f5f34a8050c958b1b6aacf627b92216c1bfa669d
--- /dev/null
+++ b/corsika/modules/BetheBlochPDG.hpp
@@ -0,0 +1,11 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/modules/energy_loss/BetheBlochPDG.hpp>
diff --git a/corsika/modules/hadronic_elastic_model/HadronicElasticModel.hpp b/corsika/modules/HadronicElasticModel.hpp
similarity index 65%
rename from corsika/modules/hadronic_elastic_model/HadronicElasticModel.hpp
rename to corsika/modules/HadronicElasticModel.hpp
index d925a80a8d88bc4f869dec4638ba886c3ce38fd5..0789ab6b269ac7a375774ea0c7ba4d9833626eee 100644
--- a/corsika/modules/hadronic_elastic_model/HadronicElasticModel.hpp
+++ b/corsika/modules/HadronicElasticModel.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -30,32 +28,30 @@ namespace corsika::hadronic_elastic_model {
   class HadronicElasticInteraction
       : public corsika::InteractionProcess<HadronicElasticInteraction> {
   private:
-    corsika::units::si::CrossSectionType const fX, fY;
+    CrossSectionType const fX, fY;
 
     static double constexpr gfEpsilon = 0.0808;
     static double constexpr gfEta = 0.4525;
     // Froissart-Martin is not violated up for sqrt s < 10^32 eV with these values [DL].
 
-    using SquaredHEPEnergyType = decltype(corsika::units::si::HEPEnergyType() *
-                                          corsika::units::si::HEPEnergyType());
+    using SquaredHEPEnergyType = decltype(HEPEnergyType() * HEPEnergyType());
 
-    using eV2 = decltype(units::si::square(units::si::electronvolt));
-    using inveV2 = decltype(1 / units::si::square(units::si::electronvolt));
+    using eV2 = decltype(square(electronvolt));
+    using inveV2 = decltype(1 / square(electronvolt));
 
     corsika::RNG& fRNG =
         corsika::RNGManager::GetInstance().GetRandomStream("HadronicElasticModel");
 
     inveV2 B(eV2 s) const;
-    corsika::units::si::CrossSectionType CrossSection(SquaredHEPEnergyType s) const;
+    CrossSectionType CrossSection(SquaredHEPEnergyType s) const;
 
   public:
     HadronicElasticInteraction( // x & y values taken from DL for pp collisions
-        units::si::CrossSectionType x = 0.0217 * units::si::barn,
-        units::si::CrossSectionType y = 0.05608 * units::si::barn);
+        CrossSectionType x = 0.0217 * barn, CrossSectionType y = 0.05608 * barn);
     void Init();
 
     template <typename Particle>
-    corsika::units::si::GrammageType GetInteractionLength(Particle const& p);
+    GrammageType GetInteractionLength(Particle const& p);
 
     template <typename Particle>
     corsika::process::EProcessReturn DoInteraction(Particle&);
@@ -63,4 +59,4 @@ namespace corsika::hadronic_elastic_model {
 
 } // namespace corsika::hadronic_elastic_model
 
-#include <corsika/details/modules/hadronic_elastic_model/HadronicElasticModel.inl>
+#include <corsika/details/modules/HadronicElasticModel.inl>
diff --git a/corsika/modules/null_model/NullModel.hpp b/corsika/modules/NullModel.hpp
similarity index 53%
rename from corsika/modules/null_model/NullModel.hpp
rename to corsika/modules/NullModel.hpp
index 9a6fe250bc2015d6aaea940139103396f7b38146..936b1f829070a9ed0a5ae6b114d0b61d9f8550fd 100644
--- a/corsika/modules/null_model/NullModel.hpp
+++ b/corsika/modules/NullModel.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,16 +9,15 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/BaseProcess.hpp>
+#include <corsika/framework/process/BaseProcess.hpp>
 
 namespace corsika::null_model {
 
   class NullModel : public corsika::BaseProcess<NullModel> {
-    corsika::units::si::LengthType const fMaxStepLength;
+    LengthType const fMaxStepLength;
 
   public:
-    NullModel(corsika::units::si::LengthType maxStepLength =
-                  corsika::units::si::meter * std::numeric_limits<double>::infinity());
+    NullModel(LengthType maxStepLength = meter * std::numeric_limits<double>::infinity());
 
     void Init();
 
@@ -28,9 +25,9 @@ namespace corsika::null_model {
     corsika::EProcessReturn DoContinuous(Particle&, Track&) const;
 
     template <typename Particle, typename Track>
-    corsika::units::si::LengthType MaxStepLength(Particle&, Track&) const;
+    LengthType MaxStepLength(Particle&, Track&) const;
   };
 
 } // namespace corsika::null_model
 
-#include <corsika/detail/modules/null_model/NullModel.inl>
+#include <corsika/detail/modules/NullModel.inl>
diff --git a/corsika/modules/observation_plane/ObservationPlane.hpp b/corsika/modules/ObservationPlane.hpp
similarity index 74%
rename from corsika/modules/observation_plane/ObservationPlane.hpp
rename to corsika/modules/ObservationPlane.hpp
index 40bfd18966afd68fdc128fdab8672b5085525865..a6b817ee5041dd29bfeeac175b8e314acbdf50b9 100644
--- a/corsika/modules/observation_plane/ObservationPlane.hpp
+++ b/corsika/modules/ObservationPlane.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -12,7 +10,7 @@
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Plane.hpp>
-#include <corsika/framework/sequence/ContinuousProcess.hpp>
+#include <corsika/framework/process/ContinuousProcess.hpp>
 #include <corsika/setup/SetupStack.hpp>
 #include <corsika/setup/SetupTrajectory.hpp>
 
@@ -35,9 +33,8 @@ namespace corsika::observation_plane {
         corsika::setup::Stack::ParticleType const& vParticle,
         corsika::setup::Trajectory const& vTrajectory);
 
-    corsika::units::si::LengthType MaxStepLength(
-        corsika::setup::Stack::ParticleType const&,
-        corsika::setup::Trajectory const& vTrajectory);
+    LengthType MaxStepLength(corsika::setup::Stack::ParticleType const&,
+                             corsika::setup::Trajectory const& vTrajectory);
 
   private:
     corsika::Plane const plane_;
@@ -46,4 +43,4 @@ namespace corsika::observation_plane {
   };
 } // namespace corsika::observation_plane
 
-#include <corsika/detail/modules/observation_plane/ObservationPlane.inl>
+#include <corsika/detail/modules/ObservationPlane.inl>
diff --git a/corsika/modules/particle_cut/ParticleCut.hpp b/corsika/modules/ParticleCut.hpp
similarity index 57%
rename from corsika/modules/particle_cut/ParticleCut.hpp
rename to corsika/modules/ParticleCut.hpp
index 57ef280bd688829a38db100db4e495d0eea6334b..0858abc4b4631070658c49678d486ed1116660e3 100644
--- a/corsika/modules/particle_cut/ParticleCut.hpp
+++ b/corsika/modules/ParticleCut.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -12,23 +10,23 @@
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/SecondariesProcess.hpp>
+#include <corsika/framework/process/SecondariesProcess.hpp>
 #include <corsika/setup/SetupStack.hpp>
 
 namespace corsika::particle_cut {
 
   class ParticleCut : public corsika::SecondariesProcess<ParticleCut> {
 
-    units::si::HEPEnergyType const fECut;
+    HEPEnergyType const fECut;
 
-    units::si::HEPEnergyType fEnergy = 0 * units::si::electronvolt;
-    units::si::HEPEnergyType fEmEnergy = 0 * units::si::electronvolt;
+    HEPEnergyType fEnergy = 0 * electronvolt;
+    HEPEnergyType fEmEnergy = 0 * electronvolt;
     unsigned int fEmCount = 0;
-    units::si::HEPEnergyType fInvEnergy = 0 * units::si::electronvolt;
+    HEPEnergyType fInvEnergy = 0 * electronvolt;
     unsigned int fInvCount = 0;
 
   public:
-    ParticleCut(const units::si::HEPEnergyType vCut)
+    ParticleCut(const HEPEnergyType vCut)
         : fECut(vCut) {}
 
     bool ParticleIsInvisible(corsika::Code) const;
@@ -42,13 +40,13 @@ namespace corsika::particle_cut {
     void Init();
     void ShowResults();
 
-    units::si::HEPEnergyType GetInvEnergy() const { return fInvEnergy; }
-    units::si::HEPEnergyType GetCutEnergy() const { return fEnergy; }
-    units::si::HEPEnergyType GetEmEnergy() const { return fEmEnergy; }
+    HEPEnergyType GetInvEnergy() const { return fInvEnergy; }
+    HEPEnergyType GetCutEnergy() const { return fEnergy; }
+    HEPEnergyType GetEmEnergy() const { return fEmEnergy; }
     unsigned int GetNumberEmParticles() const { return fEmCount; }
     unsigned int GetNumberInvParticles() const { return fInvCount; }
   };
 
 } // namespace corsika::particle_cut
 
-#include <corsika/detail/modules/particle_cut/ParticleCut.inl>
+#include <corsika/detail/modules/ParticleCut.inl>
diff --git a/corsika/modules/Pythia8.hpp b/corsika/modules/Pythia8.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fdf773ad7a10d8376d59db3694a5d9193f395b7
--- /dev/null
+++ b/corsika/modules/Pythia8.hpp
@@ -0,0 +1,12 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/modules/pythia8/Decay.hpp>
+#include <corsika/modules/pythia8/Interaction.hpp>
diff --git a/corsika/modules/QGSJetII.hpp b/corsika/modules/QGSJetII.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9540c4ad116471d54a5ef178124bd97b979d9758
--- /dev/null
+++ b/corsika/modules/QGSJetII.hpp
@@ -0,0 +1,11 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/modules/qgsjetII/Interaction.hpp>
diff --git a/corsika/modules/Sibyll.hpp b/corsika/modules/Sibyll.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..49ba49b7640da1bc752385b9c7fa9c991e730092
--- /dev/null
+++ b/corsika/modules/Sibyll.hpp
@@ -0,0 +1,13 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/modules/sibyll/Interaction.hpp>
+#include <corsika/modules/sibyll/Decay.hpp>
+#include <corsika/modules/sibyll/NuclearInteraction.hpp>
diff --git a/corsika/modules/stack_inspector/StackInspector.hpp b/corsika/modules/StackInspector.hpp
similarity index 56%
rename from corsika/modules/stack_inspector/StackInspector.hpp
rename to corsika/modules/StackInspector.hpp
index b688da526a85c86e255844abd47eb193c7aa59b9..22f65e7fc442d072e3dd2fc6122e86f40de6e702 100644
--- a/corsika/modules/stack_inspector/StackInspector.hpp
+++ b/corsika/modules/StackInspector.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,8 +9,7 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/StackProcess.hpp>
-#include <corsika/setup/SetupTrajectory.hpp>
+#include <corsika/framework/process/StackProcess.hpp>
 
 #include <chrono>
 
@@ -26,8 +23,7 @@ namespace corsika::stack_inspector {
     using corsika::StackProcess<StackInspector<TStack>>::GetStep;
 
   public:
-    StackInspector(const int vNStep, const bool vReportStack,
-                   const corsika::units::si::HEPEnergyType vE0);
+    StackInspector(const int vNStep, const bool vReportStack, const HEPEnergyType vE0);
     ~StackInspector();
 
     void Init();
@@ -36,18 +32,15 @@ namespace corsika::stack_inspector {
     /**
      * To set a new E0, for example when a new shower event is started
      */
-    void SetE0(const corsika::units::si::HEPEnergyType vE0) { E0_ = vE0; }
+    void SetE0(const HEPEnergyType vE0) { E0_ = vE0; }
 
   private:
     bool ReportStack_;
-    corsika::units::si::HEPEnergyType E0_;
-    const corsika::units::si::HEPEnergyType dE_threshold_ = std::invoke([]() {
-      using namespace units::si;
-      return 1_eV;
-    });
+    HEPEnergyType E0_;
+    const HEPEnergyType dE_threshold_ = std::invoke([]() { return 1_eV; });
     decltype(std::chrono::system_clock::now()) StartTime_;
   };
 
 } // namespace corsika::stack_inspector
 
-#include <corsika/detail/modules/stack_inspector/StackInspector.inl>
+#include <corsika/detail/modules/StackInspector.inl>
diff --git a/corsika/modules/switch_process/SwitchProcess.hpp b/corsika/modules/SwitchProcess.hpp
similarity index 80%
rename from corsika/modules/switch_process/SwitchProcess.hpp
rename to corsika/modules/SwitchProcess.hpp
index 13c2d4b35bb5237d97dc10a436e1202e262d34b4..d6d0ec52f43f738bc79867c09a2bd6e54df23725 100644
--- a/corsika/modules/switch_process/SwitchProcess.hpp
+++ b/corsika/modules/SwitchProcess.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,9 +9,8 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
-#include <corsika/framework/sequence/ProcessSequence.hpp>
-#include <corsika/setup/SetupStack.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
+#include <corsika/framework/process/ProcessSequence.hpp>
 
 namespace corsika::switch_process {
 
@@ -29,11 +26,11 @@ namespace corsika::switch_process {
   class SwitchProcess : public BaseProcess<SwitchProcess<TLowEProcess, THighEProcess>> {
     TLowEProcess& fLowEProcess;
     THighEProcess& fHighEProcess;
-    units::si::HEPEnergyType const fThresholdEnergy;
+    HEPEnergyType const fThresholdEnergy;
 
   public:
     SwitchProcess(TLowEProcess& vLowEProcess, THighEProcess& vHighEProcess,
-                  units::si::HEPEnergyType vThresholdEnergy)
+                  HEPEnergyType vThresholdEnergy)
         : fLowEProcess(vLowEProcess)
         , fHighEProcess(vHighEProcess)
         , fThresholdEnergy(vThresholdEnergy) {}
@@ -44,12 +41,12 @@ namespace corsika::switch_process {
     }
 
     template <typename TParticle>
-    corsika::units::si::InverseGrammageType GetInverseInteractionLength(TParticle& p) {
+    InverseGrammageType GetInverseInteractionLength(TParticle& p) {
       return 1 / GetInteractionLength(p);
     }
 
     template <typename TParticle>
-    units::si::GrammageType GetInteractionLength(TParticle& vParticle) {
+    GrammageType GetInteractionLength(TParticle& vParticle) {
       if (vParticle.GetEnergy() < fThresholdEnergy) {
         if constexpr (is_process_sequence_v<TLowEProcess>) {
           return fLowEProcess.GetTotalInteractionLength(vParticle);
@@ -69,10 +66,9 @@ namespace corsika::switch_process {
     // implement DoInteraction() because we want to call SelectInteraction
     // in case a member process is a ProcessSequence.
     template <typename TParticle, typename TSecondaries>
-    EProcessReturn SelectInteraction(
-        TParticle& vP, TSecondaries& vS,
-        [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_select,
-        corsika::units::si::InverseGrammageType& lambda_inv_count) {
+    EProcessReturn SelectInteraction(TParticle& vP, TSecondaries& vS,
+                                     [[maybe_unused]] InverseGrammageType lambda_select,
+                                     InverseGrammageType& lambda_inv_count) {
       if (vP.GetEnergy() < fThresholdEnergy) {
         if constexpr (is_process_sequence_v<TLowEProcess>) {
           return fLowEProcess.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
diff --git a/corsika/modules/track_writer/TrackWriter.hpp b/corsika/modules/TrackWriter.hpp
similarity index 72%
rename from corsika/modules/track_writer/TrackWriter.hpp
rename to corsika/modules/TrackWriter.hpp
index 07603722caba548a28a429f8897d38900b4d7f46..3f1341d8a9e2c10aafe8548b1fc89c5d3764be8a 100644
--- a/corsika/modules/track_writer/TrackWriter.hpp
+++ b/corsika/modules/TrackWriter.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,7 +9,7 @@
 #pragma once
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/sequence/ContinuousProcess.hpp>
+#include <corsika/framework/process/ContinuousProcess.hpp>
 
 #include <fstream>
 #include <string>
@@ -30,7 +28,7 @@ namespace corsika::track_writer {
     corsika::EProcessReturn DoContinuous(const Particle&, const Track&);
 
     template <typename Particle, typename Track>
-    corsika::units::si::LengthType MaxStepLength(const Particle&, const Track&);
+    LengthType MaxStepLength(const Particle&, const Track&);
 
   private:
     std::string const fFilename;
@@ -42,4 +40,4 @@ namespace corsika::track_writer {
 
 } // namespace corsika::track_writer
 
-#include <corsika/detail/modules/track_writer/TrackWriter.inl>
+#include <corsika/detail/modules/TrackWriter.inl>
diff --git a/corsika/modules/tracking_line/TrackingLine.hpp b/corsika/modules/TrackingLine.hpp
similarity index 71%
rename from corsika/modules/tracking_line/TrackingLine.hpp
rename to corsika/modules/TrackingLine.hpp
index f93f931f198eb97e3acf0d01f98ebd2d70dfd2ea..e33a94d46ef091f2bb0159a0584d5f6ded8cd1c9 100644
--- a/corsika/modules/tracking_line/TrackingLine.hpp
+++ b/corsika/modules/TrackingLine.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -21,20 +19,12 @@
 #include <type_traits>
 #include <utility>
 
-namespace corsika {
-  template <typename IEnvironmentModel>
-  class Environment;
-  template <typename IEnvironmentModel>
-  class VolumeTreeNode;
-} // namespace corsika
-
 namespace corsika::tracking_line {
 
-  std::optional<std::pair<corsika::units::si::TimeType, corsika::units::si::TimeType>>
-  TimeOfIntersection(corsika::Line const&, corsika::Sphere const&);
+  std::optional<std::pair<TimeType, TimeType>> TimeOfIntersection(Line const&,
+                                                                  Sphere const&);
 
-  corsika::units::si::TimeType TimeOfIntersection(corsika::Line const&,
-                                                  corsika::Plane const&);
+  TimeType TimeOfIntersection(Line const&, Plane const&);
 
   class TrackingLine {
 
@@ -44,28 +34,22 @@ namespace corsika::tracking_line {
     template <typename Particle> // was Stack previously, and argument was
                                  // Stack::StackIterator
     auto GetTrack(Particle const& p) {
-      using namespace corsika::units::si;
-      corsika::Vector<SpeedType::dimension_type> const velocity =
-          p.GetMomentum() / p.GetEnergy() * corsika::units::constants::c;
+      Vector<SpeedType::dimension_type> const velocity =
+          p.GetMomentum() / p.GetEnergy() * constants::c;
 
       auto const currentPosition = p.GetPosition();
       std::cout << "TrackingLine pid: " << p.GetPID()
                 << " , E = " << p.GetEnergy() / 1_GeV << " GeV" << std::endl;
-      std::cout << "TrackingLine pos: "
-                << currentPosition.GetCoordinates()
-                // << " [" << p.GetNode()->GetModelProperties().GetName() << "]"
-                << std::endl;
+      std::cout << "TrackingLine pos: " << currentPosition.GetCoordinates() << std::endl;
       std::cout << "TrackingLine   E: " << p.GetEnergy() / 1_GeV << " GeV" << std::endl;
       std::cout << "TrackingLine   p: " << p.GetMomentum().GetComponents() / 1_GeV
                 << " GeV " << std::endl;
       std::cout << "TrackingLine   v: " << velocity.GetComponents() << std::endl;
 
       // to do: include effect of magnetic field
-      corsika::Line line(currentPosition, velocity);
+      Line line(currentPosition, velocity);
 
       auto const* currentLogicalVolumeNode = p.GetNode();
-      //~ auto const* currentNumericalVolumeNode =
-      //~ fEnvironment.GetUniverse()->GetContainingNode(currentPosition);
       auto const numericallyInside =
           currentLogicalVolumeNode->GetVolume().Contains(currentPosition);
 
@@ -79,7 +63,7 @@ namespace corsika::tracking_line {
       // for entering from outside
       auto addIfIntersects = [&](auto const& vtn) {
         auto const& volume = vtn.GetVolume();
-        auto const& sphere = dynamic_cast<corsika::Sphere const&>(
+        auto const& sphere = dynamic_cast<Sphere const&>(
             volume); // for the moment we are a bit bold here and assume
         // everything is a sphere, crashes with exception if not
 
@@ -101,7 +85,7 @@ namespace corsika::tracking_line {
 
       {
         auto const& sphere =
-            dynamic_cast<corsika::Sphere const&>(currentLogicalVolumeNode->GetVolume());
+            dynamic_cast<Sphere const&>(currentLogicalVolumeNode->GetVolume());
         // for the moment we are a bit bold here and assume
         // everything is a sphere, crashes with exception if not
         [[maybe_unused]] auto const [t1, t2] = *TimeOfIntersection(line, sphere);
@@ -128,11 +112,11 @@ namespace corsika::tracking_line {
                 // << " " << minIter->second->GetModelProperties().GetName()
                 << std::endl;
 
-      return std::make_tuple(corsika::Trajectory<corsika::Line>(line, min),
-                             velocity.norm() * min, minIter->second);
+      return std::make_tuple(Trajectory<Line>(line, min), velocity.norm() * min,
+                             minIter->second);
     }
   };
 
 } // namespace corsika::tracking_line
 
-#include <corsika/detail/modules/tracking_line/TrackingLine.inl>
+#include <corsika/detail/modules/TrackingLine.inl>
diff --git a/corsika/modules/UrQMD.hpp b/corsika/modules/UrQMD.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a29165307efa5c5c5b3df6d14e9ec3c6badd79f1
--- /dev/null
+++ b/corsika/modules/UrQMD.hpp
@@ -0,0 +1,11 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/modules/urqmd/UrQMD.hpp>
diff --git a/corsika/modules/energy_loss/BetheBlochPDG.hpp b/corsika/modules/energy_loss/BetheBlochPDG.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..85fe0bceeae0af46d886ecc49fd9cdf3c3938a9a
--- /dev/null
+++ b/corsika/modules/energy_loss/BetheBlochPDG.hpp
@@ -0,0 +1,67 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/geometry/Point.hpp>
+#include <corsika/framework/geometry/Vector.hpp>
+#include <corsika/framework/process/ContinuousProcess.hpp>
+
+#include <corsika/setup/SetupStack.hpp>
+#include <corsika/setup/SetupTrajectory.hpp>
+
+#include <map>
+
+namespace corsika::energy_loss {
+
+  class BetheBlochPDG : public corsika::ContinuousProcess<BetheBlochPDG> {
+
+    using MeVgcm2 = decltype(1e6 * electronvolt / gram * square(1e-2 * meter));
+
+    void MomentumUpdate(setup::Stack::ParticleType&, HEPEnergyType Enew);
+
+  public:
+    template <typename TDim>
+    BetheBlochPDG(corsika::Point const& injectionPoint,
+                  corsika::Vector<TDim> const& direction)
+        : InjectionPoint_(injectionPoint)
+        , ShowerAxisDirection_(direction.normalized()) {}
+
+    BetheBlochPDG(setup::Trajectory const& trajectory)
+        : BetheBlochPDG(trajectory.GetPosition(0), trajectory.GetV0()){};
+
+    void Init() {}
+    corsika::EProcessReturn DoContinuous(setup::Stack::ParticleType&,
+                                         setup::Trajectory const&);
+    LengthType MaxStepLength(setup::Stack::ParticleType const&,
+                             setup::Trajectory const&) const;
+    HEPEnergyType GetTotal() const { return BetheBlochPDGTot_; }
+    void PrintProfile() const;
+    static HEPEnergyType BetheBloch(setup::Stack::ParticleType const&,
+                                    const GrammageType);
+    static HEPEnergyType RadiationLosses(setup::Stack::ParticleType const&,
+                                         const GrammageType);
+    static HEPEnergyType TotalEnergyLoss(setup::Stack::ParticleType const&,
+                                         const GrammageType);
+
+  private:
+    void FillProfile(setup::Stack::ParticleType const&, setup::Trajectory const&,
+                     HEPEnergyType);
+
+    HEPEnergyType BetheBlochPDGTot_ = HEPEnergyType::zero();
+    std::map<int, HEPEnergyType> Profile_; // longitudinal profile
+    corsika::Point const InjectionPoint_;
+    corsika::Vector<dimensionless_d> const ShowerAxisDirection_;
+    GrammageType const dX_ = 10_g / square(1_cm); // profile binning
+    const GrammageType dX_threshold_ = 0.0001_g / square(1_cm);
+  };
+
+} // namespace corsika::energy_loss
+
+#include <corsika/detail/modules/energy_loss/BetheBlochPDG.inl>
diff --git a/corsika/modules/energy_loss/EnergyLoss.hpp b/corsika/modules/energy_loss/EnergyLoss.hpp
deleted file mode 100644
index ea3682a8b452a1dde6a658384e384a3333249fc4..0000000000000000000000000000000000000000
--- a/corsika/modules/energy_loss/EnergyLoss.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
- *
- * This software is distributed under the terms of the GNU General Public
- * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
- * the license.
- */
-
-#pragma once
-
-#include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/geometry/Point.hpp>
-#include <corsika/framework/geometry/Vector.hpp>
-#include <corsika/framework/sequence/ContinuousProcess.hpp>
-
-#include <corsika/setup/SetupStack.hpp>
-#include <corsika/setup/SetupTrajectory.hpp>
-
-#include <map>
-
-namespace corsika::energy_loss {
-
-  class EnergyLoss : public corsika::ContinuousProcess<EnergyLoss> {
-
-    using MeVgcm2 = decltype(1e6 * units::si::electronvolt / units::si::gram *
-                             units::si::square(1e-2 * units::si::meter));
-
-    void MomentumUpdate(setup::Stack::ParticleType&, units::si::HEPEnergyType Enew);
-
-  public:
-    template <typename TDim>
-    EnergyLoss(corsika::Point const& injectionPoint,
-               corsika::Vector<TDim> const& direction)
-        : InjectionPoint_(injectionPoint)
-        , ShowerAxisDirection_(direction.normalized()) {}
-
-    EnergyLoss(setup::Trajectory const& trajectory)
-        : EnergyLoss(trajectory.GetPosition(0), trajectory.GetV0()){};
-
-    void Init() {}
-    corsika::EProcessReturn DoContinuous(setup::Stack::ParticleType&,
-                                         setup::Trajectory const&);
-    units::si::LengthType MaxStepLength(setup::Stack::ParticleType const&,
-                                        setup::Trajectory const&) const;
-    units::si::HEPEnergyType GetTotal() const { return EnergyLossTot_; }
-    void PrintProfile() const;
-    static units::si::HEPEnergyType BetheBloch(setup::Stack::ParticleType const&,
-                                               const units::si::GrammageType);
-    static units::si::HEPEnergyType RadiationLosses(setup::Stack::ParticleType const&,
-                                                    const units::si::GrammageType);
-    static units::si::HEPEnergyType TotalEnergyLoss(setup::Stack::ParticleType const&,
-                                                    const units::si::GrammageType);
-
-  private:
-    void FillProfile(setup::Stack::ParticleType const&, setup::Trajectory const&,
-                     units::si::HEPEnergyType);
-    // void FillProfileAbsorbed(setup::Stack::ParticleType const&, setup::Trajectory
-    // const&);
-
-    units::si::HEPEnergyType EnergyLossTot_ = units::si::HEPEnergyType::zero();
-    units::si::GrammageType const dX_ = std::invoke([]() {
-      using namespace units::si;
-      return 10_g / square(1_cm);
-    });                                               // profile binning
-    std::map<int, units::si::HEPEnergyType> Profile_; // longitudinal profile
-    corsika::Point const InjectionPoint_;
-    corsika::Vector<units::si::dimensionless_d> const ShowerAxisDirection_;
-  };
-
-  const units::si::GrammageType dX_threshold_ = std::invoke([]() {
-    using namespace units::si;
-    return 0.0001_g / square(1_cm);
-  });
-
-} // namespace corsika::energy_loss
-
-#include <corsika/detail/modules/energy_loss/EnergyLoss.inl>
diff --git a/corsika/modules/pythia8/Decay.hpp b/corsika/modules/pythia8/Decay.hpp
index 80e185dec31a2a2a05f78c3bf5b49b2ccca720b3..d80f0779be086984aa8ccaea5605153f44cb4d81 100644
--- a/corsika/modules/pythia8/Decay.hpp
+++ b/corsika/modules/pythia8/Decay.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -11,13 +9,15 @@
 #pragma once
 
 #include <corsika/framework/core/ParticleProperties.hpp>
-#include <corsika/framework/sequence/DecayProcess.hpp>
+#include <corsika/framework/process/DecayProcess.hpp>
+#include <corsika/framework/geometry/Vector.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 
 #include <corsika/modules/pythia8/Pythia8.hpp>
 
 namespace corsika::pythia8 {
 
-  typedef corsika::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
+  typedef corsika::Vector<hepmomentum_d> MomentumVector;
 
   class Decay : public corsika::DecayProcess<Decay> {
     const std::vector<corsika::Code> fTrackedParticles;
@@ -33,7 +33,7 @@ namespace corsika::pythia8 {
     void SetStable(const corsika::Code);
 
     template <typename TParticle>
-    corsika::units::si::TimeType GetLifetime(TParticle const&);
+    TimeType GetLifetime(TParticle const&);
 
     template <typename TProjectile>
     void DoDecay(TProjectile&);
diff --git a/corsika/modules/pythia8/Interaction.hpp b/corsika/modules/pythia8/Interaction.hpp
index 452ff29cc8226fda128692a3dad5abcea3a87d3f..e76a46508dd7ee5043a9d2855cf345b9d35ab05c 100644
--- a/corsika/modules/pythia8/Interaction.hpp
+++ b/corsika/modules/pythia8/Interaction.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -13,7 +11,7 @@
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/modules/pythia8/Pythia8.hpp>
 
 #include <tuple>
@@ -36,20 +34,17 @@ namespace corsika::pythia8 {
     void SetStable(const corsika::Code);
 
     bool WasInitialized() { return fInitialized; }
-    bool ValidCoMEnergy(corsika::units::si::HEPEnergyType ecm) {
-      using namespace corsika::units::si;
-      return (10_GeV < ecm) && (ecm < 1_PeV);
-    }
+    bool ValidCoMEnergy(HEPEnergyType ecm) { return (10_GeV < ecm) && (ecm < 1_PeV); }
 
     bool CanInteract(const corsika::Code);
     void ConfigureLabFrameCollision(const corsika::Code, const corsika::Code,
-                                    const corsika::units::si::HEPEnergyType);
-    std::tuple<corsika::units::si::CrossSectionType, corsika::units::si::CrossSectionType>
-    GetCrossSection(const corsika::Code BeamId, const corsika::Code TargetId,
-                    const corsika::units::si::HEPEnergyType CoMenergy);
+                                    const HEPEnergyType);
+    std::tuple<CrossSectionType, CrossSectionType> GetCrossSection(
+        const corsika::Code BeamId, const corsika::Code TargetId,
+        const HEPEnergyType CoMenergy);
 
     template <typename TParticle>
-    corsika::units::si::GrammageType GetInteractionLength(TParticle&);
+    GrammageType GetInteractionLength(TParticle&);
 
     /**
        In this function PYTHIA is called to produce one event. The
diff --git a/corsika/modules/pythia8/Pythia8.hpp b/corsika/modules/pythia8/Pythia8.hpp
index 4ea2cef62885cd9cac3a2869cdc753c7d4c1738e..5b42ac148b97a9bc54059d27d3a34c61f4d8b87a 100644
--- a/corsika/modules/pythia8/Pythia8.hpp
+++ b/corsika/modules/pythia8/Pythia8.hpp
@@ -1,3 +1,11 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
 #pragma once
 
 #include <Pythia8/Pythia.h>
diff --git a/corsika/modules/pythia8/Random.hpp b/corsika/modules/pythia8/Random.hpp
index 7cb03e553d2a462455100d4087ca46b383d54f4c..75d9681eeb7c79f51fdbf15567cd083aafa81bc7 100644
--- a/corsika/modules/pythia8/Random.hpp
+++ b/corsika/modules/pythia8/Random.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/modules/qgsjetII/Interaction.hpp b/corsika/modules/qgsjetII/Interaction.hpp
index 2498bb9f36936c6eaaa118067f61640d3216064e..6a129d609d40c25a4f9477ce4595b82b3ed67327 100644
--- a/corsika/modules/qgsjetII/Interaction.hpp
+++ b/corsika/modules/qgsjetII/Interaction.hpp
@@ -1,8 +1,6 @@
 /*
  * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
- * See file AUTHORS for a list of contributors.
- *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
@@ -13,7 +11,10 @@
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
+
+#include <corsika/modules/qgsjetII/Random.hpp>
+#include <qgsjet-II-04.hpp>
 
 #include <string>
 
@@ -38,12 +39,12 @@ namespace corsika::qgsjetII {
              corsika::IsNucleus(TargetId);
     }
 
-    corsika::units::si::CrossSectionType GetCrossSection(
-        const corsika::Code, const corsika::Code, const corsika::units::si::HEPEnergyType,
-        const unsigned int Abeam = 0, const unsigned int Atarget = 0) const;
+    CrossSectionType GetCrossSection(const corsika::Code, const corsika::Code,
+                                     const HEPEnergyType, const unsigned int Abeam = 0,
+                                     const unsigned int Atarget = 0) const;
 
     template <typename TParticle>
-    corsika::units::si::GrammageType GetInteractionLength(TParticle const&) const;
+    GrammageType GetInteractionLength(TParticle const&) const;
 
     /**
        In this function QGSJETII is called to produce one event. The
diff --git a/corsika/modules/qgsjetII/ParticleConversion.hpp b/corsika/modules/qgsjetII/ParticleConversion.hpp
index ff60913707863c30b927877f5f18d2417880541b..4ff13340338c3720312ad5ed8f1e1a8ae30b1d50 100644
--- a/corsika/modules/qgsjetII/ParticleConversion.hpp
+++ b/corsika/modules/qgsjetII/ParticleConversion.hpp
@@ -1,8 +1,6 @@
 /*
  * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
- * See file AUTHORS for a list of contributors.
- *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
diff --git a/corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp b/corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp
index 84c90873ebd28ededf341bc0a6bede00b75f4828..012368cd10ff64da73136c9b335008cc5c8f21f5 100644
--- a/corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp
+++ b/corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp
@@ -1,8 +1,6 @@
 /*
  * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
- * See file AUTHORS for a list of contributors.
- *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
@@ -15,7 +13,8 @@
 #include <corsika/framework/geometry/Vector.hpp>
 #include <corsika/framework/stack/Stack.hpp>
 #include <corsika/modules/qgsjetII/ParticleConversion.hpp>
-#include <corsika/modules/qgsjetII/qgsjet-II-04.hpp>
+
+#include <qgsjet-II-04.hpp>
 
 namespace corsika::qgsjetII {
 
diff --git a/corsika/modules/qgsjetII/QGSJetIIStack.hpp b/corsika/modules/qgsjetII/QGSJetIIStack.hpp
index eca8669e06156f345c8476ee6abf4eebae630b5c..6103447fad7501293117324697e3d3d0f9850265 100644
--- a/corsika/modules/qgsjetII/QGSJetIIStack.hpp
+++ b/corsika/modules/qgsjetII/QGSJetIIStack.hpp
@@ -1,8 +1,6 @@
 /*
  * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
- * See file AUTHORS for a list of contributors.
- *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
@@ -15,11 +13,12 @@
 #include <corsika/framework/geometry/Vector.hpp>
 #include <corsika/framework/stack/Stack.hpp>
 #include <corsika/modules/qgsjetII/ParticleConversion.hpp>
-#include <corsika/modules/qgsjetII/qgsjet-II-04.hpp>
+
+#include <qgsjet-II-04.hpp>
 
 namespace corsika::qgsjetII {
 
-  typedef corsika::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
+  typedef corsika::Vector<hepmomentum_d> MomentumVector;
 
   class QGSJetIIStackData {
 
@@ -36,13 +35,11 @@ namespace corsika::qgsjetII {
     unsigned int GetCapacity() const { return nptmax; }
 
     void SetId(const unsigned int i, const int v) { qgarr14_.ich[i] = v; }
-    void SetEnergy(const unsigned int i, const corsika::units::si::HEPEnergyType v) {
-      using namespace corsika::units::si;
+    void SetEnergy(const unsigned int i, const HEPEnergyType v) {
       qgarr14_.esp[i][0] = v / 1_GeV;
     }
 
     void SetMomentum(const unsigned int i, const MomentumVector& v) {
-      using namespace corsika::units::si;
       auto tmp = v.GetComponents();
       qgarr14_.esp[i][2] = tmp[0] / 1_GeV;
       qgarr14_.esp[i][3] = tmp[1] / 1_GeV;
@@ -50,13 +47,9 @@ namespace corsika::qgsjetII {
     }
 
     int GetId(const unsigned int i) const { return qgarr14_.ich[i]; }
-    corsika::units::si::HEPEnergyType GetEnergy(const int i) const {
-      using namespace corsika::units::si;
-      return qgarr14_.esp[i][0] * 1_GeV;
-    }
+    HEPEnergyType GetEnergy(const int i) const { return qgarr14_.esp[i][0] * 1_GeV; }
     MomentumVector GetMomentum(const unsigned int i,
                                const corsika::CoordinateSystem& CS) const {
-      using namespace corsika::units::si;
       corsika::QuantityVector<hepmomentum_d> components = {qgarr14_.esp[i][2] * 1_GeV,
                                                            qgarr14_.esp[i][3] * 1_GeV,
                                                            qgarr14_.esp[i][1] * 1_GeV};
@@ -87,30 +80,24 @@ namespace corsika::qgsjetII {
     using corsika::ParticleBase<StackIteratorInterface>::GetIndex;
 
   public:
-    void SetParticleData(const int vID, const corsika::units::si::HEPEnergyType vE,
-                         const MomentumVector& vP,
-                         const corsika::units::si::HEPMassType vM) {
+    void SetParticleData(const int vID, const HEPEnergyType vE, const MomentumVector& vP,
+                         const HEPMassType vM) {
       SetPID(vID);
       SetEnergy(vE);
       SetMomentum(vP);
     }
 
     void SetParticleData(ParticleInterface<StackIteratorInterface>& /*parent*/,
-                         const int vID, const corsika::units::si::HEPEnergyType vE,
-                         const MomentumVector& vP,
-                         const corsika::units::si::HEPMassType vM) {
+                         const int vID, const HEPEnergyType vE, const MomentumVector& vP,
+                         const HEPMassType vM) {
       SetPID(vID);
       SetEnergy(vE);
       SetMomentum(vP);
     }
 
-    void SetEnergy(const corsika::units::si::HEPEnergyType v) {
-      GetStackData().SetEnergy(GetIndex(), v);
-    }
+    void SetEnergy(const HEPEnergyType v) { GetStackData().SetEnergy(GetIndex(), v); }
 
-    corsika::units::si::HEPEnergyType GetEnergy() const {
-      return GetStackData().GetEnergy(GetIndex());
-    }
+    HEPEnergyType GetEnergy() const { return GetStackData().GetEnergy(GetIndex()); }
 
     void SetPID(const int v) { GetStackData().SetId(GetIndex(), v); }
 
diff --git a/corsika/modules/qgsjetII/Random.hpp b/corsika/modules/qgsjetII/Random.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..626a5e274337da1f5dd6e22862d965eda7286cd3
--- /dev/null
+++ b/corsika/modules/qgsjetII/Random.hpp
@@ -0,0 +1,23 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/random/RNGManager.hpp>
+#include <random>
+
+namespace qgsjetII {
+
+  double rndm_interface() {
+    static corsika::RNG& rng =
+        corsika::RNGManager::GetInstance().GetRandomStream("qgran");
+    std::uniform_real_distribution<double> dist;
+    return dist(rng);
+  }
+
+} // namespace qgsjetII
diff --git a/corsika/modules/qgsjetII/qgsjet-II-04.hpp b/corsika/modules/qgsjetII/qgsjet-II-04.hpp
index 20cbb40dc6eb2ab7858d351615c6cb6899b7300c..f95d011ae1c1a7784a40aef7012eb2d05e32a6cf 100644
--- a/corsika/modules/qgsjetII/qgsjet-II-04.hpp
+++ b/corsika/modules/qgsjetII/qgsjet-II-04.hpp
@@ -1,8 +1,6 @@
 /*
  * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
- * See file AUTHORS for a list of contributors.
- *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
@@ -99,64 +97,6 @@ double qgsect_(const double& e0n, const int& icz, const int& iap0, const int& ia
    link to random number generation
  */
 double qgran_(int&);
-
-/**
-   dummy function from CRMC
- */
-void lzmaopenfile_(const char* name, int length);
-void lzmaclosefile_();
-void lzmafillarray_(const double& dum, const int& idum);
 }
 
 #include <corsika/detail/modules/qgsjetII/qgsjet-II-04.inl>
-
-/**
- * WARNING, TODO, FIXME: this below here has to go away, this is just a dummy until
- * we "properly" link to the external corsika-data submodule
- */
-
-namespace corsika_data {
-
-  void CorDataOpenFile(const std::string&) {
-    throw std::runtime_error(
-        "CorDataOpenFile: Cannot read compressed data files with dummy library.");
-  }
-  void CorDataFillArray(double*, const int&) {
-    throw std::runtime_error(
-        "CorDataFillArray: Cannot read compressed data files with dummy library.");
-  }
-  void CorDataCloseFile() {
-    throw std::runtime_error(
-        "CorDataCloseFile: Cannot read compressed data files with dummy library.");
-  }
-  double CorDataNextNumber() {
-    throw std::runtime_error(
-        "CorDataNextNumber: Cannot read compressed data files with dummy library.");
-    return 0;
-  }
-  void CorDataNextText(std::string&) {
-    throw std::runtime_error(
-        "CorDataNextText(string&): Cannot read compressed data files with dummy "
-        "library.");
-  }
-  void CorDataNextText(char*, int) {
-    throw std::runtime_error(
-        "CorDataNextText(char*): Cannot read compressed data files with dummy library.");
-  }
-  bool CorDataCanDeCompress() { return false; }
-
-  // the fortran interface functions
-  extern "C" {
-  void cordataopenfile_(const char* name) { CorDataOpenFile(name); }
-  void cordatafillarray_(double* data, const int& length) {
-    CorDataFillArray(data, length);
-  }
-  void cordataclosefile_() { CorDataCloseFile(); }
-  double cordatanextnumber_() { return CorDataNextNumber(); }
-  void cordatanexttext_(char*, int) {
-    throw std::runtime_error(
-        "cordatanexttext_: Cannot read compressed data files with dummy library.");
-  }
-  int cordatacandecompress_() { return 0; }
-  }
-} // namespace corsika_data
diff --git a/corsika/modules/sibyll/Decay.hpp b/corsika/modules/sibyll/Decay.hpp
index a906d5027cf36b977985fc7a34eb0239550892a1..6d6210e386e4529d3cec04b2be26871434ea636f 100644
--- a/corsika/modules/sibyll/Decay.hpp
+++ b/corsika/modules/sibyll/Decay.hpp
@@ -11,7 +11,7 @@
 #include <corsika/modules/sibyll/Random.hpp>
 
 #include <corsika/framework/core/ParticleProperties.hpp>
-#include <corsika/framework/sequence/DecayProcess.hpp>
+#include <corsika/framework/process/DecayProcess.hpp>
 
 #include <set>
 #include <vector>
@@ -64,7 +64,7 @@ namespace corsika::sibyll {
     void SetHandleAllDecay();
 
     template <typename TParticle>
-    corsika::units::si::TimeType GetLifetime(TParticle const&) const;
+    TimeType GetLifetime(TParticle const&) const;
 
     /**
      In this function SIBYLL is called to produce to decay the input particle.
diff --git a/corsika/modules/sibyll/Interaction.hpp b/corsika/modules/sibyll/Interaction.hpp
index e60cb69e2b676b10a54bb18783bb38d86068bf2c..ce091811cf96453b962a71e94a5f932dedc76a27 100644
--- a/corsika/modules/sibyll/Interaction.hpp
+++ b/corsika/modules/sibyll/Interaction.hpp
@@ -13,7 +13,7 @@
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
 #include <tuple>
 
 namespace corsika::sibyll {
@@ -39,23 +39,22 @@ namespace corsika::sibyll {
     void SetAllStable();
 
     bool WasInitialized() { return initialized_; }
-    bool IsValidCoMEnergy(corsika::units::si::HEPEnergyType ecm) const {
+    bool IsValidCoMEnergy(HEPEnergyType ecm) const {
       return (minEnergyCoM_ <= ecm) && (ecm <= maxEnergyCoM_);
     }
     int GetMaxTargetMassNumber() const { return maxTargetMassNumber_; }
-    corsika::units::si::HEPEnergyType GetMinEnergyCoM() const { return minEnergyCoM_; }
-    corsika::units::si::HEPEnergyType GetMaxEnergyCoM() const { return maxEnergyCoM_; }
+    HEPEnergyType GetMinEnergyCoM() const { return minEnergyCoM_; }
+    HEPEnergyType GetMaxEnergyCoM() const { return maxEnergyCoM_; }
     bool IsValidTarget(corsika::Code TargetId) const {
       return (corsika::GetNucleusA(TargetId) < maxTargetMassNumber_) &&
              corsika::IsNucleus(TargetId);
     }
 
-    std::tuple<corsika::units::si::CrossSectionType, corsika::units::si::CrossSectionType>
-    GetCrossSection(const corsika::Code, const corsika::Code,
-                    const corsika::units::si::HEPEnergyType) const;
+    std::tuple<CrossSectionType, CrossSectionType> GetCrossSection(
+        const corsika::Code, const corsika::Code, const HEPEnergyType) const;
 
     template <typename TParticle>
-    corsika::units::si::GrammageType GetInteractionLength(TParticle const&) const;
+    GrammageType GetInteractionLength(TParticle const&) const;
 
     /**
        In this function SIBYLL is called to produce one event. The
@@ -77,10 +76,8 @@ namespace corsika::sibyll {
         corsika::Code::DPlus,     corsika::Code::DMinus,     corsika::Code::D0,
         corsika::Code::MuMinus,   corsika::Code::MuPlus,     corsika::Code::D0Bar};
     const bool internalDecays_ = true;
-    const corsika::units::si::HEPEnergyType minEnergyCoM_ =
-        10. * 1e9 * corsika::units::si::electronvolt;
-    const corsika::units::si::HEPEnergyType maxEnergyCoM_ =
-        1.e6 * 1e9 * corsika::units::si::electronvolt;
+    const HEPEnergyType minEnergyCoM_ = 10. * 1e9 * electronvolt;
+    const HEPEnergyType maxEnergyCoM_ = 1.e6 * 1e9 * electronvolt;
     const int maxTargetMassNumber_ = 18;
   };
 
diff --git a/corsika/modules/sibyll/NuclearInteraction.hpp b/corsika/modules/sibyll/NuclearInteraction.hpp
index 583bc89a9ed6898b330f0695cca8d69164e794ab..d7f75d90bf4a481160e3ddacc1104eecdfe1b5b2 100644
--- a/corsika/modules/sibyll/NuclearInteraction.hpp
+++ b/corsika/modules/sibyll/NuclearInteraction.hpp
@@ -10,7 +10,7 @@
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
 
 namespace corsika::sibyll {
 
@@ -35,24 +35,19 @@ namespace corsika::sibyll {
 
     void InitializeNuclearCrossSections();
     void PrintCrossSectionTable(corsika::Code);
-    corsika::units::si::CrossSectionType ReadCrossSectionTable(
-        const int, corsika::Code, corsika::units::si::HEPEnergyType);
-    corsika::units::si::HEPEnergyType GetMinEnergyPerNucleonCoM() {
-      return gMinEnergyPerNucleonCoM_;
-    }
-    corsika::units::si::HEPEnergyType GetMaxEnergyPerNucleonCoM() {
-      return gMaxEnergyPerNucleonCoM_;
-    }
+    CrossSectionType ReadCrossSectionTable(const int, corsika::Code, HEPEnergyType);
+    HEPEnergyType GetMinEnergyPerNucleonCoM() { return gMinEnergyPerNucleonCoM_; }
+    HEPEnergyType GetMaxEnergyPerNucleonCoM() { return gMaxEnergyPerNucleonCoM_; }
     unsigned int constexpr GetMaxNucleusAProjectile() { return gMaxNucleusAProjectile_; }
     unsigned int constexpr GetMaxNFragments() { return gMaxNFragments_; }
     unsigned int constexpr GetNEnergyBins() { return gNEnBins_; }
 
     template <typename Particle>
-    std::tuple<corsika::units::si::CrossSectionType, corsika::units::si::CrossSectionType>
-    GetCrossSection(Particle const& p, const corsika::Code TargetId);
+    std::tuple<CrossSectionType, CrossSectionType> GetCrossSection(
+        Particle const& p, const corsika::Code TargetId);
 
     template <typename Particle>
-    corsika::units::si::GrammageType GetInteractionLength(Particle const&);
+    GrammageType GetInteractionLength(Particle const&);
 
     template <typename TSecondaryView>
     corsika::EProcessReturn DoInteraction(TSecondaryView&);
@@ -69,10 +64,8 @@ namespace corsika::sibyll {
     static constexpr unsigned int gMaxNFragments_ = 60;
     // energy limits defined by table used for cross section in signuc.f
     // 10**1 GeV to 10**6 GeV
-    static constexpr corsika::units::si::HEPEnergyType gMinEnergyPerNucleonCoM_ =
-        10. * 1e9 * corsika::units::si::electronvolt;
-    static constexpr corsika::units::si::HEPEnergyType gMaxEnergyPerNucleonCoM_ =
-        1.e6 * 1e9 * corsika::units::si::electronvolt;
+    static constexpr HEPEnergyType gMinEnergyPerNucleonCoM_ = 10. * 1e9 * electronvolt;
+    static constexpr HEPEnergyType gMaxEnergyPerNucleonCoM_ = 1.e6 * 1e9 * electronvolt;
   };
 
 } // namespace corsika::sibyll
diff --git a/corsika/modules/sibyll/ParticleConversion.hpp b/corsika/modules/sibyll/ParticleConversion.hpp
index fc27b648ae3f3335d40fa6d37921d52f0289f987..27a1f856d0c246301ffe01db7749ea711c816ab7 100644
--- a/corsika/modules/sibyll/ParticleConversion.hpp
+++ b/corsika/modules/sibyll/ParticleConversion.hpp
@@ -59,7 +59,7 @@ namespace corsika::sibyll {
 
   bool constexpr CanInteract(corsika::Code pCode) { return GetSibyllXSCode(pCode) > 0; }
 
-  corsika::units::si::HEPMassType GetSibyllMass(corsika::Code const);
+  HEPMassType GetSibyllMass(corsika::Code const);
 
 } // namespace corsika::sibyll
 
diff --git a/corsika/modules/sibyll/SibStack.hpp b/corsika/modules/sibyll/SibStack.hpp
index cbdf4fb8378ed6ccc09ac0b04a1723a534c5b157..9240995d0fa91abc482e7473054ce2779b7fc48b 100644
--- a/corsika/modules/sibyll/SibStack.hpp
+++ b/corsika/modules/sibyll/SibStack.hpp
@@ -18,7 +18,7 @@
 
 namespace corsika::sibyll {
 
-  typedef corsika::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
+  typedef corsika::Vector<hepmomentum_d> MomentumVector;
 
   class SibStackData {
 
@@ -30,34 +30,21 @@ namespace corsika::sibyll {
     unsigned int GetCapacity() const { return 8000; }
 
     void SetId(const unsigned int i, const int v) { s_plist_.llist[i] = v; }
-    void SetEnergy(const unsigned int i, const corsika::units::si::HEPEnergyType v) {
-      using namespace corsika::units::si;
+    void SetEnergy(const unsigned int i, const HEPEnergyType v) {
       s_plist_.p[3][i] = v / 1_GeV;
     }
-    void SetMass(const unsigned int i, const corsika::units::si::HEPMassType v) {
-      using namespace corsika::units::si;
+    void SetMass(const unsigned int i, const HEPMassType v) {
       s_plist_.p[4][i] = v / 1_GeV;
     }
     void SetMomentum(const unsigned int i, const MomentumVector& v) {
-      using namespace corsika::units::si;
       auto tmp = v.GetComponents();
       for (int idx = 0; idx < 3; ++idx) s_plist_.p[idx][i] = tmp[idx] / 1_GeV;
     }
 
     int GetId(const unsigned int i) const { return s_plist_.llist[i]; }
-    corsika::units::si::HEPEnergyType GetEnergy(const int i) const {
-      using namespace corsika::units::si;
-      return s_plist_.p[3][i] * 1_GeV;
-    }
-    corsika::units::si::HEPEnergyType GetMass(const unsigned int i) const {
-      using namespace corsika::units::si;
-      return s_plist_.p[4][i] * 1_GeV;
-    }
+    HEPEnergyType GetEnergy(const int i) const { return s_plist_.p[3][i] * 1_GeV; }
+    HEPEnergyType GetMass(const unsigned int i) const { return s_plist_.p[4][i] * 1_GeV; }
     MomentumVector GetMomentum(const unsigned int i) const {
-      using corsika::CoordinateSystem;
-      using corsika::QuantityVector;
-      using corsika::RootCoordinateSystem;
-      using namespace corsika::units::si;
       CoordinateSystem& rootCS =
           RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
       QuantityVector<hepmomentum_d> components = {
@@ -90,9 +77,8 @@ namespace corsika::sibyll {
 
   public:
     void SetParticleData(const int vID, // corsika::sibyll::SibyllCode vID,
-                         const corsika::units::si::HEPEnergyType vE,
-                         const MomentumVector& vP,
-                         const corsika::units::si::HEPMassType vM) {
+                         const HEPEnergyType vE, const MomentumVector& vP,
+                         const HEPMassType vM) {
       SetPID(vID);
       SetEnergy(vE);
       SetMomentum(vP);
@@ -101,32 +87,23 @@ namespace corsika::sibyll {
 
     void SetParticleData(ParticleInterface<StackIteratorInterface>& /*parent*/,
                          const int vID, //  corsika::sibyll::SibyllCode vID,
-                         const corsika::units::si::HEPEnergyType vE,
-                         const MomentumVector& vP,
-                         const corsika::units::si::HEPMassType vM) {
+                         const HEPEnergyType vE, const MomentumVector& vP,
+                         const HEPMassType vM) {
       SetPID(vID);
       SetEnergy(vE);
       SetMomentum(vP);
       SetMass(vM);
     }
 
-    void SetEnergy(const corsika::units::si::HEPEnergyType v) {
-      GetStackData().SetEnergy(GetIndex(), v);
-    }
+    void SetEnergy(const HEPEnergyType v) { GetStackData().SetEnergy(GetIndex(), v); }
 
-    corsika::units::si::HEPEnergyType GetEnergy() const {
-      return GetStackData().GetEnergy(GetIndex());
-    }
+    HEPEnergyType GetEnergy() const { return GetStackData().GetEnergy(GetIndex()); }
 
     bool HasDecayed() const { return abs(GetStackData().GetId(GetIndex())) > 100; }
 
-    void SetMass(const corsika::units::si::HEPMassType v) {
-      GetStackData().SetMass(GetIndex(), v);
-    }
+    void SetMass(const HEPMassType v) { GetStackData().SetMass(GetIndex(), v); }
 
-    corsika::units::si::HEPEnergyType GetMass() const {
-      return GetStackData().GetMass(GetIndex());
-    }
+    HEPEnergyType GetMass() const { return GetStackData().GetMass(GetIndex()); }
 
     void SetPID(const int v) { GetStackData().SetId(GetIndex(), v); }
 
diff --git a/corsika/modules/urqmd/Random.hpp b/corsika/modules/urqmd/Random.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0754d11ee7061bf08742d85e8a2ebbfa28a1dde6
--- /dev/null
+++ b/corsika/modules/urqmd/Random.hpp
@@ -0,0 +1,26 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/random/RNGManager.hpp>
+#include <random>
+
+namespace urqmd {
+
+  /**
+   * the random number generator function of UrQMD
+   */
+  double rndm_interface() {
+    static corsika::RNG& rng =
+        corsika::RNGManager::GetInstance().GetRandomStream("UrQMD");
+    static std::uniform_real_distribution<double> dist;
+    return dist(rng);
+  }
+
+} // namespace urqmd
diff --git a/corsika/modules/urqmd/UrQMD.hpp b/corsika/modules/urqmd/UrQMD.hpp
index 04c70b6c490508f97d97582a604d961d774f4242..55fc39e7eb0d2a7e71d852ea9e1d4e6847177664 100644
--- a/corsika/modules/urqmd/UrQMD.hpp
+++ b/corsika/modules/urqmd/UrQMD.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -12,10 +10,13 @@
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/InteractionProcess.hpp>
+
 #include <corsika/setup/SetupStack.hpp>
 
+#include <corsika/modules/urqmd/Random.hpp>
+
 #include <array>
 #include <utility>
 
@@ -25,107 +26,23 @@ namespace corsika::urqmd {
   public:
     UrQMD();
     void Init() {}
-    corsika::units::si::GrammageType GetInteractionLength(
-        corsika::setup::Stack::StackIterator&) const;
+    GrammageType GetInteractionLength(corsika::setup::Stack::StackIterator&) const;
 
     template <typename TParticle>
-    corsika::units::si::CrossSectionType GetCrossSection(TParticle const&,
-                                                         corsika::Code) const;
+    CrossSectionType GetCrossSection(TParticle const&, corsika::Code) const;
 
     corsika::EProcessReturn DoInteraction(corsika::setup::StackView::StackIterator&);
 
     bool CanInteract(corsika::Code) const;
 
   private:
-    static corsika::units::si::CrossSectionType GetCrossSection(
-        corsika::Code, corsika::Code, corsika::units::si::HEPEnergyType, int);
+    static CrossSectionType GetCrossSection(corsika::Code, corsika::Code, HEPEnergyType,
+                                            int);
     corsika::RNG& fRNG = corsika::RNGManager::GetInstance().GetRandomStream("UrQMD");
 
     std::uniform_int_distribution<int> fBooleanDist{0, 1};
   };
 
-  namespace constants {
-    // from coms.f
-    int constexpr nmax = 500;
-
-    // from options.f
-    int constexpr numcto = 400;
-    int constexpr numctp = 400;
-
-    // from inputs.f
-    int constexpr aamax = 300;
-
-  } // namespace constants
-
-  template <typename T>
-  using nmaxArray = std::array<T, constants::nmax>;
-  using nmaxIntArray = nmaxArray<int>;
-  using nmaxDoubleArray = nmaxArray<double>;
-
-  extern "C" {
-  void iniurqmdc8_();
-  double ranf_(int&);
-  void cascinit_(int const&, int const&, int const&);
-  double nucrad_(int const&);
-  void urqmd_(int&);
-  int pdgid_(int&, int&);
-  double sigtot_(int&, int&, double&);
-
-  // defined in coms.f
-  extern struct {
-    int npart, nbar, nmes, ctag, nsteps, uid_cnt, ranseed, event;
-    int Ap; // projectile mass number (in case of nucleus)
-    int At; // target mass number (in case of nucleus)
-    int Zp; // projectile charge number (in case of nucleus)
-    int Zt; // target charge number (in case of nucleus)
-    int eos, dectag, NHardRes, NSoftRes, NDecRes, NElColl, NBlColl;
-  } sys_;
-
-  extern struct {
-    double time, acttime, bdist, bimp, bmin;
-    double ebeam; // lab-frame energy of projectile
-    double ecm;
-  } rsys_;
-
-  // defined in coms.f
-  extern struct {
-    nmaxIntArray spin, ncoll, charge, ityp, lstcoll, iso3, origin, strid, uid;
-  } isys_;
-
-  // defined in coor.f
-  extern struct {
-    nmaxDoubleArray r0, rx, ry, rz, p0, px, py, pz, fmass, rww, dectime;
-  } coor_;
-
-  // defined in inputs.f
-  extern struct {
-    int nevents;
-    std::array<int, 2> spityp; // particle codes of: [0]: projectile, [1]: target
-    int prspflg;               // projectile special flag
-    int trspflg; // target special flag, set to 1 unless target is nucleus > H
-    std::array<int, 2> spiso3; // particle codes of: [0]: projectile, [1]: target
-    int outsteps, bflag, srtflag, efuncflag, nsrt, npb, firstev;
-  } inputs_;
-
-  // defined in inputs.f
-  extern struct {
-    double srtmin, srtmax, pbeam, betann, betatar, betapro, pbmin, pbmax;
-  } input2_;
-
-  // defined in options.f
-  extern struct {
-    std::array<double, constants::numcto> CTOption;
-    std::array<double, constants::numctp> CTParam;
-  } options_;
-
-  extern struct {
-    int fixedseed, bf13, bf14, bf15, bf16, bf17, bf18, bf19, bf20;
-  } loptions_;
-
-  // defined in urqmdInterface.F
-  extern struct { std::array<double, 3> xs, bim; } cxs_u2_;
-  }
-
   /**
    * convert CORSIKA code to UrQMD code tuple
    *
diff --git a/corsika/setup/SetupEnvironment.hpp b/corsika/setup/SetupEnvironment.hpp
index 4fc78db671e50530eb93bfa0fed55f3dc12f1300..be970d2b17391eaf035a49457d828a0abf3b20a4 100644
--- a/corsika/setup/SetupEnvironment.hpp
+++ b/corsika/setup/SetupEnvironment.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/setup/SetupLogger.hpp b/corsika/setup/SetupLogger.hpp
index 939c7d3596c4136257a4df27479943866b041ecb..4d90f4c383fec6fcc8700cbfbb78d121b7ecdbc9 100644
--- a/corsika/setup/SetupLogger.hpp
+++ b/corsika/setup/SetupLogger.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/corsika/setup/SetupStack.hpp b/corsika/setup/SetupStack.hpp
index b1ae3810381b86ab5fd96fa62b59ced5e295a3ca..8bb07507a6519f3ee2ff4fe3bdc536e17be4c7aa 100644
--- a/corsika/setup/SetupStack.hpp
+++ b/corsika/setup/SetupStack.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -186,8 +186,9 @@ namespace corsika::setup {
       actually needed. Keep an eye on this!
     */
 #if defined(__clang__)
-  using StackView = corsika::SecondaryView<typename corsika::Stack::StackImpl,
-                                           corsika::detail::StackWithGeometryInterface>;
+  using StackView =
+      corsika::SecondaryView<typename corsika::setup::Stack::StackImpl,
+                             corsika::setup::detail::StackWithGeometryInterface>;
 #elif defined(__GNUC__) || defined(__GNUG__)
   using StackView = corsika::MakeView<corsika::setup::Stack>::type;
 #endif
diff --git a/corsika/setup/SetupTrajectory.hpp b/corsika/setup/SetupTrajectory.hpp
index c3e839d01ed91c16c4c04a239f208dbaa8700d08..38b055a1b3850e9cb7a72b3fa130adfdacbac750 100644
--- a/corsika/setup/SetupTrajectory.hpp
+++ b/corsika/setup/SetupTrajectory.hpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -53,29 +53,15 @@ namespace corsika::setup {
   
   namespace testing {
 
-    template <typename TTrack>
-    TTrack make_track(const corsika::geometry::Line& line,
-                      const corsika::units::si::TimeType tEnd);
-
-    template <>
-    inline corsika::geometry::LineTrajectory
-    make_track<corsika::geometry::LineTrajectory>(
-        const corsika::geometry::Line& line, const corsika::units::si::TimeType tEnd) {
-      return corsika::geometry::LineTrajectory(line, tEnd);
+  /// helper visitor to modify Particle by moving along Trajectory
+  class GetDuration {
+  public:
+    TimeType operator()(std::monostate const&) {
+      return 0 * second;
     }
-
-    template <>
-    inline corsika::geometry::LeapFrogTrajectory
-    make_track<corsika::geometry::LeapFrogTrajectory>(
-        const corsika::geometry::Line& line, const corsika::units::si::TimeType tEnd) {
-      using namespace corsika::units::si;
-      typedef corsika::geometry::Vector<magnetic_flux_density_d> MagneticFieldVector;
-
-      auto const k = square(0_m) / (square(1_s) * 1_V);
-      return corsika::geometry::LeapFrogTrajectory(
-          line.GetR0(), line.GetV0(),
-          MagneticFieldVector{line.GetR0().GetCoordinateSystem(), 0_T, 0_T, 0_T}, k,
-          tEnd);
+    template <typename T>
+    TimeType operator()(T const& trajectory) {
+      return trajectory.GetDuration();
     }
   };
   */
diff --git a/corsika/stack/DummyStack.hpp b/corsika/stack/DummyStack.hpp
index 64934107b1dbfd35d823c289663d60b7121b3f63..af216984330b251a49876ec2499a69c31ef29891 100644
--- a/corsika/stack/DummyStack.hpp
+++ b/corsika/stack/DummyStack.hpp
@@ -8,6 +8,7 @@
 
 #pragma once
 
+
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/stack/Stack.hpp>
@@ -17,7 +18,6 @@
 
 namespace corsika {
 
-  namespace dummy {
 
     /**
      * Example of a particle object on the stack, with NO DATA.
@@ -33,19 +33,13 @@ namespace corsika {
     };
 
     template <typename StackIteratorInterface>
-    class ParticleInterface
-        : public corsika::stack::ParticleBase<StackIteratorInterface> {
-
-    protected:
-      using corsika::stack::ParticleBase<StackIteratorInterface>::GetStack;
-      using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData;
+    struct ParticleInterface : public corsika::ParticleBase<StackIteratorInterface> {
 
-    public:
-      using corsika::stack::ParticleBase<StackIteratorInterface>::GetIndex;
+    	typedef corsika::ParticleBase<StackIteratorInterface> super_type;
 
     public:
       void SetParticleData(const std::tuple<NoData>& /*v*/) {}
-      void SetParticleData(ParticleInterface<StackIteratorInterface>& /*parent*/,
+      void SetParticleData(super_type& /*parent*/,
                            const std::tuple<NoData>& /*v*/) {}
 
       std::string as_string() const { return "dummy-data"; }
@@ -59,20 +53,38 @@ namespace corsika {
     class DummyStackImpl {
 
     public:
-      void Init() { entries_ = 0; }
+    DummyStackImpl()=default;
+
+    DummyStackImpl( DummyStackImpl const&)=default;
+
+    DummyStackImpl(DummyStackImpl &&)=default;
 
-      void Clear() { entries_ = 0; }
+    DummyStackImpl& operator=( DummyStackImpl const& )=default;
+    DummyStackImpl& operator=( DummyStackImpl && )=default;
 
-      int GetSize() const { return entries_; }
-      int GetCapacity() const { return entries_; }
+
+      void init() { entries_ = 0; }
+
+      void clear() { entries_ = 0; }
+
+      int getSize() const { return entries_; }
+      int getCapacity() const { return entries_; }
 
       /**
        *   Function to copy particle at location i2 in stack to i1
        */
-      void Copy(const int /*i1*/, const int /*i2*/) {}
+      void copy(const int /*i1*/, const int /*i2*/) {}
+
+      void incrementSize() { entries_++; }
+      void decrementSize() { entries_--; }
+
+	int getEntries() const {
+		return entries_;
+	}
 
-      void IncrementSize() { entries_++; }
-      void DecrementSize() { entries_--; }
+	void setEntries(int entries = 0) {
+		entries_ = entries;
+	}
 
     private:
       int entries_ = 0;
@@ -81,6 +93,5 @@ namespace corsika {
 
     typedef Stack<DummyStackImpl, ParticleInterface> DummyStack;
 
-  } // namespace dummy
 
 } // namespace corsika
diff --git a/corsika/stack/GeometryNodeStackExtension.hpp b/corsika/stack/GeometryNodeStackExtension.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c0c89b74e18d294477dfe2cf303c834723eb3f6
--- /dev/null
+++ b/corsika/stack/GeometryNodeStackExtension.hpp
@@ -0,0 +1,145 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+//#include <corsika/framework/logging/Logging.hpp>
+#include <corsika/framework/stack/Stack.hpp>
+
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace corsika::stack::node {
+
+  /**
+   * @class GeometryDataInterface
+   *
+   * corresponding defintion of a stack-readout object, the iteractor
+   * dereference operator will deliver access to these function
+  // defintion of a stack-readout object, the iteractor dereference
+  // operator will deliver access to these function
+   */
+
+  /**
+   * \fixme Document type T
+   */
+  template <typename T, typename TEnvType>
+  struct GeometryDataInterface : public T {
+
+    typedef T super_type;
+
+  public:
+
+    typedef typename TEnvType::BaseNodeType node_type;
+
+    // default version for particle-creation from input data
+    void setParticleData(const std::tuple<node_type const*> v) {
+      setNode(std::get<0>(v));
+    }
+    void setParticleData(GeometryDataInterface& parent,
+                         const std::tuple<node_type const*>) {
+      setNode(parent.getNode()); // copy Node from parent particle!
+    }
+    void setParticleData() { setNode(nullptr); }
+    void setParticleData(GeometryDataInterface& parent) {
+      setNode(parent.getNode()); // copy Node from parent particle!
+    }
+
+    std::string as_string() const {
+    	return fmt::format("node={}", fmt::ptr(getNode()));
+    }
+
+    void setNode(node_type const* v) {
+    	super_type::GetStackData().setNode(super_type::GetIndex(), v);
+    }
+
+    node_type const* getNode() const {
+    	return super_type::GetStackData().getNode(super_type::GetIndex());
+    }
+  };
+
+  // definition of stack-data object to store geometry information
+
+
+  /**
+   * @class GeometryData
+   *
+   * definition of stack-data object to store geometry information
+   */
+  template <typename TEnvType>
+  class GeometryData {
+
+  public:
+
+	typedef typename TEnvType::BaseNodeType node_type;
+	typedef std::vector<const node_type*>   node_vector_type;
+
+	GeometryData()= default;
+
+	GeometryData( GeometryData<TEnvType> const& )= default;
+
+	GeometryData( GeometryData<TEnvType> && )= default;
+
+	GeometryData<TEnvType>&
+	operator=( GeometryData<TEnvType> const& )= default;
+
+	GeometryData<TEnvType>&
+	operator=( GeometryData<TEnvType> && )= default;
+
+    // these functions are needed for the Stack interface
+    void clear() {
+    	node_vector_.clear();
+    }
+
+    unsigned int getSize() const {
+    	return node_vector_.size();
+    }
+
+    unsigned int getCapacity() const {
+    	return node_vector_.size();
+    }
+
+    void copy(const int i1, const int i2) {
+    	node_vector_[i2] = node_vector_[i1];
+    }
+
+    void swap(const int i1, const int i2) {
+    	std::swap(node_vector_[i1], node_vector_[i2]);
+    }
+
+    // custom data access function
+    void setNode(const int i, node_type const* v) {
+    	node_vector_[i] = v;
+    }
+
+    node_type const* getNode(const int i) const {
+    	return node_vector_[i];
+    }
+
+    // these functions are also needed by the Stack interface
+    void incrementSize() {
+    	node_vector_.push_back(nullptr);
+    }
+
+    void decrementSize() {
+      if (node_vector_.size() > 0) { node_vector_.pop_back(); }
+    }
+
+    // custom private data section
+  private:
+
+    node_vector_type node_vector_;
+  };
+
+  template <typename T, typename TEnv>
+  struct MakeGeometryDataInterface {
+    typedef GeometryDataInterface<T, TEnv> type;
+  };
+
+} // namespace corsika::stack::node
diff --git a/corsika/stack/NuclearStackExtension.hpp b/corsika/stack/NuclearStackExtension.hpp
index a8dc432303b6f296d326141b3b9af2e415c13532..ac433e4de5724fe94aa83b4ea9284cb1c39be787 100644
--- a/corsika/stack/NuclearStackExtension.hpp
+++ b/corsika/stack/NuclearStackExtension.hpp
@@ -11,9 +11,9 @@
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/stack/Stack.hpp>
-
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/Vector.hpp>
+#include <corsika/stack/SuperStupidStack.hpp>
 
 #include <corsika/logging/Logging.h>
 
@@ -23,367 +23,372 @@
 
 namespace corsika {
 
-  /**
-   * @namespace nuclear_extension
-   *
-   * Add A and Z data to existing stack (currently SuperStupidStack) of particle
-   * properties. This is done via inheritance, not via CombinedStack since the nuclear
-   * data is stored ONLY when needed (for nuclei) and not for all particles. Thus, this is
-   * a new, derived Stack object.
-   *
-   * Only for Code::Nucleus particles A and Z are stored, not for all
-   * normal elementary particles.
-   *
-   * Thus in your code, make sure to always check <code>
-   * particle.GetPID()==Code::Nucleus </code> before attempting to
-   * read any nuclear information.
-   *
-   *
-   */
-
-  typedef corsika::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
-
-  namespace nuclear_extension {
-
-    /**
-     * @class NuclearParticleInterface
-     *
-     * Define ParticleInterface for NuclearStackExtension Stack derived from
-     * ParticleInterface of Inner stack class
-     */
-    template <template <typename> typename InnerParticleInterface,
-              typename StackIteratorInterface>
-    class NuclearParticleInterface
-        : public InnerParticleInterface<StackIteratorInterface> {
-
-    protected:
-      using InnerParticleInterface<StackIteratorInterface>::GetStackData;
-      using InnerParticleInterface<StackIteratorInterface>::GetIndex;
-      using InnerParticleInterface<StackIteratorInterface>::as_string;
-
-    public:
-      void SetParticleData(
-          const std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                           corsika::MomentumVector, corsika::Point,
-                           corsika::units::si::TimeType>& v) {
-        if (std::get<0>(v) == corsika::Code::Nucleus) {
-          std::ostringstream err;
-          err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
-          throw std::runtime_error(err.str());
-        }
-        InnerParticleInterface<StackIteratorInterface>::SetParticleData(v);
-        SetNucleusRef(-1); // this is not a nucleus
-      }
-
-      void SetParticleData(
-          const std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                           corsika::MomentumVector, corsika::Point,
-                           corsika::units::si::TimeType, unsigned short, unsigned short>&
-              v) {
-        const unsigned short A = std::get<5>(v);
-        const unsigned short Z = std::get<6>(v);
-        if (std::get<0>(v) != corsika::Code::Nucleus || A == 0 || Z == 0) {
-          std::ostringstream err;
-          err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
-          throw std::runtime_error(err.str());
-        }
-        SetNucleusRef(GetStackData().GetNucleusNextRef()); // store this nucleus data ref
-        SetNuclearA(A);
-        SetNuclearZ(Z);
-        InnerParticleInterface<StackIteratorInterface>::SetParticleData(
-            std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                       corsika::MomentumVector, corsika::Point,
-                       corsika::units::si::TimeType>{std::get<0>(v), std::get<1>(v),
-                                                     std::get<2>(v), std::get<3>(v),
-                                                     std::get<4>(v)});
-      }
-
-      void SetParticleData(
-          InnerParticleInterface<StackIteratorInterface>& p,
-          const std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                           corsika::MomentumVector, corsika::Point,
-                           corsika::units::si::TimeType>& v) {
-        if (std::get<0>(v) == corsika::Code::Nucleus) {
-          std::ostringstream err;
-          err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
-          throw std::runtime_error(err.str());
-        }
-        InnerParticleInterface<StackIteratorInterface>::SetParticleData(
-            p, std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                          corsika::MomentumVector, corsika::Point,
-                          corsika::units::si::TimeType>{std::get<0>(v), std::get<1>(v),
-                                                        std::get<2>(v), std::get<3>(v),
-                                                        std::get<4>(v)});
-        SetNucleusRef(-1); // this is not a nucleus
-      }
-
-      void SetParticleData(
-          InnerParticleInterface<StackIteratorInterface>& p,
-          const std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                           corsika::MomentumVector, corsika::Point,
-                           corsika::units::si::TimeType, unsigned short, unsigned short>&
-              v) {
-        const unsigned short A = std::get<5>(v);
-        const unsigned short Z = std::get<6>(v);
-        if (std::get<0>(v) != corsika::Code::Nucleus || A == 0 || Z == 0) {
-          std::ostringstream err;
-          err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
-          throw std::runtime_error(err.str());
-        }
-        SetNucleusRef(GetStackData().GetNucleusNextRef()); // store this nucleus data ref
-        SetNuclearA(A);
-        SetNuclearZ(Z);
-        InnerParticleInterface<StackIteratorInterface>::SetParticleData(
-            p, std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                          corsika::MomentumVector, corsika::Point,
-                          corsika::units::si::TimeType>{std::get<0>(v), std::get<1>(v),
-                                                        std::get<2>(v), std::get<3>(v),
-                                                        std::get<4>(v)});
-      }
-
-      std::string as_string() const {
-        return fmt::format(
-            "{}, nuc({})", InnerParticleInterface<StackIteratorInterface>::as_string(),
-            (isNucleus() ? fmt::format("A={}, Z={}", GetNuclearA(), GetNuclearZ())
-                         : "n/a"));
-      }
-
-      /**
-       * @name individual setters
-       * @{
-       */
-      void SetNuclearA(const unsigned short vA) {
-        GetStackData().SetNuclearA(GetIndex(), vA);
-      }
-      void SetNuclearZ(const unsigned short vZ) {
-        GetStackData().SetNuclearZ(GetIndex(), vZ);
-      }
-      /// @}
-
-      /**
-       * @name individual getters
-       * @{
-       */
-      int GetNuclearA() const { return GetStackData().GetNuclearA(GetIndex()); }
-      int GetNuclearZ() const { return GetStackData().GetNuclearZ(GetIndex()); }
-      /// @}
-
-      /**
-       * Overwrite normal GetParticleMass function with nuclear version
-       */
-      corsika::units::si::HEPMassType GetMass() const {
-        if (InnerParticleInterface<StackIteratorInterface>::GetPID() ==
-            corsika::Code::Nucleus)
-          return corsika::GetNucleusMass(GetNuclearA(), GetNuclearZ());
-        return InnerParticleInterface<StackIteratorInterface>::GetMass();
-      }
-      /**
-       * Overwirte normal GetChargeNumber function with nuclear version
-       **/
-      int16_t GetChargeNumber() const {
-        if (InnerParticleInterface<StackIteratorInterface>::GetPID() ==
-            corsika::Code::Nucleus)
-          return GetNuclearZ();
-        return InnerParticleInterface<StackIteratorInterface>::GetChargeNumber();
-      }
-
-      int GetNucleusRef() const {
-        return GetStackData().GetNucleusRef(GetIndex());
-      } // LCOV_EXCL_LINE
-
-    protected:
-      void SetNucleusRef(const int vR) { GetStackData().SetNucleusRef(GetIndex(), vR); }
-      bool isNucleus() const { return GetStackData().isNucleus(GetIndex()); }
-    };
-
-    /**
-     * @class NuclearStackExtension
-     *
-     * Memory implementation of adding nuclear inforamtion to the
-     * existing particle stack defined in class InnerStackImpl.
-     *
-     * Inside the NuclearStackExtension class there is a dedicated
-     * fNucleusRef index, where fNucleusRef[i] is referring to the
-     * correct A and Z for a specific particle index i. fNucleusRef[i]
-     * == -1 means that this is not a nucleus, and a subsequent call to
-     * GetNucleusA would produce an exception.
-     */
-    template <typename InnerStackImpl>
-    class NuclearStackExtensionImpl : public InnerStackImpl {
-
-    public:
-      void Init() { InnerStackImpl::Init(); }
-      void Dump() { InnerStackImpl::Dump(); }
-
-      void Clear() {
-        InnerStackImpl::Clear();
-        fNucleusRef.clear();
-        fNuclearA.clear();
-        fNuclearZ.clear();
-      }
-
-      unsigned int GetSize() const { return fNucleusRef.size(); }
-      unsigned int GetCapacity() const { return fNucleusRef.capacity(); }
-
-      void SetNuclearA(const unsigned int i, const unsigned short vA) {
-        fNuclearA[GetNucleusRef(i)] = vA;
-      }
-      void SetNuclearZ(const unsigned int i, const unsigned short vZ) {
-        fNuclearZ[GetNucleusRef(i)] = vZ;
-      }
-      void SetNucleusRef(const unsigned int i, const int v) { fNucleusRef[i] = v; }
-
-      int GetNuclearA(const unsigned int i) const { return fNuclearA[GetNucleusRef(i)]; }
-      int GetNuclearZ(const unsigned int i) const { return fNuclearZ[GetNucleusRef(i)]; }
-      // this function will create new storage for Nuclear Properties, and return the
-      // reference to it
-      int GetNucleusNextRef() {
-        fNuclearA.push_back(0);
-        fNuclearZ.push_back(0);
-        return fNuclearA.size() - 1;
-      }
-
-      int GetNucleusRef(const unsigned int i) const {
-        if (fNucleusRef[i] >= 0) return fNucleusRef[i];
-        std::ostringstream err;
-        err << "NuclearStackExtension: no nucleus at ref=" << i;
-        throw std::runtime_error(err.str());
-      }
-
-      bool isNucleus(const unsigned int i) const { return fNucleusRef[i] >= 0; }
-
-      /**
-       *   Function to copy particle at location i1 in stack to i2
-       */
-      void Copy(const unsigned int i1, const unsigned int i2) {
-        // index range check
-        if (i1 >= GetSize() || i2 >= GetSize()) {
-          std::ostringstream err;
-          err << "NuclearStackExtension: trying to access data beyond size of stack!";
-          throw std::runtime_error(err.str());
-        }
-        // copy internal particle data p[i2] = p[i1]
-        InnerStackImpl::Copy(i1, i2);
-        // check if any of p[i1] or p[i2] was a Code::Nucleus
-        const int ref1 = fNucleusRef[i1];
-        const int ref2 = fNucleusRef[i2];
-        if (ref2 < 0) {
-          if (ref1 >= 0) {
-            // i1 is nucleus, i2 is not
-            fNucleusRef[i2] = GetNucleusNextRef();
-            fNuclearA[fNucleusRef[i2]] = fNuclearA[ref1];
-            fNuclearZ[fNucleusRef[i2]] = fNuclearZ[ref1];
-          } else {
-            // neither i1 nor i2 are nuclei
-          }
-        } else {
-          if (ref1 >= 0) {
-            // both are nuclei, i2 is overwritten with nucleus i1
-            // fNucleusRef stays the same, but A and Z data is overwritten
-            fNuclearA[ref2] = fNuclearA[ref1];
-            fNuclearZ[ref2] = fNuclearZ[ref1];
-          } else {
-            // i2 is overwritten with non-nucleus i1
-            fNucleusRef[i2] = -1;                       // flag as non-nucleus
-            fNuclearA.erase(fNuclearA.cbegin() + ref2); // remove data for i2
-            fNuclearZ.erase(fNuclearZ.cbegin() + ref2); // remove data for i2
-            const int n = fNucleusRef.size(); // update fNucleusRef: indices above ref2
-                                              // must be decremented by 1
-            for (int i = 0; i < n; ++i) {
-              if (fNucleusRef[i] > ref2) { fNucleusRef[i] -= 1; }
-            }
-          }
-        }
-      }
-
-      /**
-       *   Function to copy particle at location i2 in stack to i1
-       */
-      void Swap(const unsigned int i1, const unsigned int i2) {
-        // index range check
-        if (i1 >= GetSize() || i2 >= GetSize()) {
-          std::ostringstream err;
-          err << "NuclearStackExtension: trying to access data beyond size of stack!";
-          throw std::runtime_error(err.str());
-        }
-        // swap original particle data
-        InnerStackImpl::Swap(i1, i2);
-        // swap corresponding nuclear reference data
-        std::swap(fNucleusRef[i2], fNucleusRef[i1]);
-      }
-
-      void IncrementSize() {
-        InnerStackImpl::IncrementSize();
-        fNucleusRef.push_back(-1);
-      }
-
-      void DecrementSize() {
-        InnerStackImpl::DecrementSize();
-        if (fNucleusRef.size() > 0) {
-          const int ref = fNucleusRef.back();
-          fNucleusRef.pop_back();
-          if (ref >= 0) {
-            fNuclearA.erase(fNuclearA.begin() + ref);
-            fNuclearZ.erase(fNuclearZ.begin() + ref);
-            const int n = fNucleusRef.size();
-            for (int i = 0; i < n; ++i) {
-              if (fNucleusRef[i] >= ref) { fNucleusRef[i] -= 1; }
-            }
-          }
-        }
-      }
-
-    private:
-      /// the actual memory to store particle data
-
-      std::vector<int> fNucleusRef;
-      std::vector<unsigned short> fNuclearA;
-      std::vector<unsigned short> fNuclearZ;
-
-    }; // end class NuclearStackExtensionImpl
-
-    //    template<typename StackIteratorInterface>
-    // using NuclearParticleInterfaceType<StackIteratorInterface> =
-    // NuclearParticleInterface< ,StackIteratorInterface>
-
-    // works, but requires stupd _PI class
-    // template<typename SS> using TEST =
-    // NuclearParticleInterface<corsika::super_stupid::SuperStupidStack::PIType,
-    // SS>;
-    template <typename InnerStack, template <typename> typename _PI>
-    using NuclearStackExtension =
-        Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, _PI>;
-
-    // ----
-
-    // I'm dont't manage to do this properly.......
-    /*
-    template<typename TT, typename SS> using TESTi = typename
-    NuclearParticleInterface<TT::template PIType, SS>::ExtendedParticleInterface;
-    template<typename TT, typename SS> using TEST1 = TESTi<TT, SS>;
-    template<typename SS> using TEST2 = TEST1<typename
-    corsika::super_stupid::SuperStupidStack, SS>;
-
-    using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
-    InnerStack::StackImpl>, TEST2>;
-    */
-    /*
-      // .... this should be fixed ....
-
-    template <typename InnerStack, typename SS=StackIteratorInterface>
-      //using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
-    InnerStack::StackImpl>, NuclearParticleInterface<typename InnerStack::template PIType,
-    StackIteratorInterface>::ExtendedParticleInterface>; using NuclearStackExtension =
-    Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, TEST1<typename
-    corsika::super_stupid::SuperStupidStack, SS> >;
-
-    //template <typename InnerStack>
-      //  using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
-    InnerStack::StackImpl>, TEST<typename
-    corsika::super_stupid::SuperStupidStack::PIType>>;
-    //using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
-    InnerStack::StackImpl>, TEST>;
-    */
-
-  } // namespace nuclear_extension
+/**
+ * @namespace nuclear_extension
+ *
+ * Add A and Z data to existing stack (currently SuperStupidStack) of particle
+ * properties. This is done via inheritance, not via CombinedStack since the nuclear
+ * data is stored ONLY when needed (for nuclei) and not for all particles. Thus, this is
+ * a new, derived Stack object.
+ *
+ * Only for Code::Nucleus particles A and Z are stored, not for all
+ * normal elementary particles.
+ *
+ * Thus in your code, make sure to always check <code>
+ * particle.GetPID()==Code::Nucleus </code> before attempting to
+ * read any nuclear information.
+ *
+ *
+ */
+
+
+/**
+ * @class NuclearParticleInterface
+ *
+ * Define ParticleInterface for NuclearStackExtension Stack derived from
+ * ParticleInterface of Inner stack class
+ */
+template < template <typename> class InnerParticleInterface, typename StackIteratorInterface>
+struct NuclearParticleInterface : public  InnerParticleInterface<StackIteratorInterface>  {
+
+	typedef  InnerParticleInterface<StackIteratorInterface>  super_type;
+
+
+
+public:
+
+
+	typedef std::tuple<
+			corsika::Code, corsika::units::si::HEPEnergyType,
+			momentum_type, corsika::Point,
+		    corsika::units::si::TimeType> particle_data_type;
+
+	typedef std::tuple<
+			corsika::Code, corsika::units::si::HEPEnergyType,
+			momentum_type, corsika::Point,
+			corsika::units::si::TimeType,
+			unsigned short, unsigned short> altenative_particle_data_type;
+
+
+	typedef corsika::Vector<corsika::units::si::hepmomentum_d> momentum_type;
+
+	void setParticleData(particle_data_type const& v) {
+
+		if (std::get<0>(v) == corsika::Code::Nucleus) {
+			std::ostringstream err;
+			err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
+			throw std::runtime_error(err.str());
+		}
+
+		super_type::setParticleData(v);
+		setNucleusRef(-1); // this is not a nucleus
+	}
+
+	void setParticleData( altenative_particle_data_type const& v)
+	{
+		const unsigned short A = std::get<5>(v);
+		const unsigned short Z = std::get<6>(v);
+		if (std::get<0>(v) != corsika::Code::Nucleus || A == 0 || Z == 0) {
+			std::ostringstream err;
+			err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
+			throw std::runtime_error(err.str());
+		}
+		setNucleusRef(super_type::GetStackData().getNucleusNextRef()); // store this nucleus data ref
+		setNuclearA(A);
+		setNuclearZ(Z);
+		super_type::setParticleData(particle_data_type{std::get<0>(v), std::get<1>(v),
+			std::get<2>(v), std::get<3>(v),	std::get<4>(v)});
+	}
+
+	void setParticleData( super_type& p, particle_data_type const& v)
+	{
+		if (std::get<0>(v) == corsika::Code::Nucleus) {
+			std::ostringstream err;
+			err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
+			throw std::runtime_error(err.str());
+		}
+
+		super_type::setParticleData(p, particle_data_type{std::get<0>(v), std::get<1>(v),
+			std::get<2>(v), std::get<3>(v),	std::get<4>(v)});
+
+		setNucleusRef(-1); // this is not a nucleus
+	}
+
+	void setParticleData( super_type& p, altenative_particle_data_type const& v) {
+
+		const unsigned short A = std::get<5>(v);
+		const unsigned short Z = std::get<6>(v);
+
+		if (std::get<0>(v) != corsika::Code::Nucleus || A == 0 || Z == 0) {
+			std::ostringstream err;
+			err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
+			throw std::runtime_error(err.str());
+		}
+
+		setNucleusRef(super_type::GetStackData().getNucleusNextRef()); // store this nucleus data ref
+		setNuclearA(A);
+		setNuclearZ(Z);
+		super_type::setParticleData(p, particle_data_type{std::get<0>(v), std::get<1>(v),
+			std::get<2>(v), std::get<3>(v),
+			std::get<4>(v)});
+	}
+
+	std::string as_string() const {
+		return fmt::format(
+				"{}, nuc({})", super_type::as_string(),
+				(isNucleus() ? fmt::format("A={}, Z={}", getNuclearA(), getNuclearZ())
+						: "n/a"));
+	}
+
+	/**
+	 * @name individual setters
+	 * @{
+	 */
+	void setNuclearA(const unsigned short vA) {
+		super_type::GetStackData().setNuclearA(super_type::GetIndex(), vA);
+	}
+	void setNuclearZ(const unsigned short vZ) {
+		super_type::GetStackData().setNuclearZ(super_type::GetIndex(), vZ);
+	}
+	/// @}
+
+	/**
+	 * @name individual getters
+	 * @{
+	 */
+	int getNuclearA() const { return super_type::GetStackData().getNuclearA(super_type::GetIndex()); }
+	int getNuclearZ() const { return super_type::GetStackData().getNuclearZ(super_type::GetIndex()); }
+	/// @}
+
+	/**
+	 * Overwrite normal GetParticleMass function with nuclear version
+	 */
+	corsika::units::si::HEPMassType getMass() const {
+		if (super_type::GetPID() ==
+				corsika::Code::Nucleus)
+			return corsika::GetNucleusMass(getNuclearA(), getNuclearZ());
+		return super_type::getMass();
+	}
+	/**
+	 * Overwirte normal GetChargeNumber function with nuclear version
+	 **/
+	int16_t getChargeNumber() const {
+		if (super_type::GetPID() ==
+				corsika::Code::Nucleus)
+			return getNuclearZ();
+		return super_type::getChargeNumber();
+	}
+
+	int getNucleusRef() const {
+		return super_type::GetStackData().getNucleusRef(GetIndex());
+	} // LCOV_EXCL_LINE
+
+protected:
+
+	void setNucleusRef(const int vR) {
+		super_type::GetStackData().setNucleusRef(super_type::GetIndex(), vR);
+	}
+
+	bool isNucleus() const {
+		return super_type::GetStackData().isNucleus(super_type::GetIndex());
+	}
+};
+
+/**
+ * @class NuclearStackExtension
+ *
+ * Memory implementation of adding nuclear inforamtion to the
+ * existing particle stack defined in class InnerStackImpl.
+ *
+ * Inside the NuclearStackExtension class there is a dedicated
+ * fNucleusRef index, where fNucleusRef[i] is referring to the
+ * correct A and Z for a specific particle index i. fNucleusRef[i]
+ * == -1 means that this is not a nucleus, and a subsequent call to
+ * GetNucleusA would produce an exception.
+ */
+template <typename InnerStackImpl>
+class NuclearStackExtensionImpl : public InnerStackImpl {
+
+	typedef InnerStackImpl super_type;
+
+public:
+
+	typedef std::vector<int>            nucleus_ref_type;
+	typedef std::vector<unsigned short>   nuclear_a_type;
+	typedef std::vector<unsigned short>   nuclear_z_type;
+
+
+	NuclearStackExtensionImpl()= default;
+
+	NuclearStackExtensionImpl( NuclearStackExtensionImpl<InnerStackImpl> const&)= default;
+
+	NuclearStackExtensionImpl( NuclearStackExtensionImpl<InnerStackImpl> &&)= default;
+
+	NuclearStackExtensionImpl<InnerStackImpl>&
+	operator=( NuclearStackExtensionImpl<InnerStackImpl> const&)= default;
+
+	NuclearStackExtensionImpl<InnerStackImpl>&
+	operator=( NuclearStackExtensionImpl<InnerStackImpl> &&)= default;
+
+	void init() {
+		super_type::init();
+	}
+
+	void dump() {
+		super_type::dump();
+	}
+
+	void clear() {
+		super_type::clear();
+		nucleusRef_.clear();
+		nuclearA_.clear();
+		nuclearZ_.clear();
+	}
+
+	unsigned int getSize() const {
+		return nucleusRef_.size();
+	}
+
+	unsigned int getCapacity() const {
+		return nucleusRef_.capacity();
+	}
+
+	void setNuclearA(const unsigned int i, const unsigned short vA) {
+		nuclearA_[getNucleusRef(i)] = vA;
+	}
+
+	void setNuclearZ(const unsigned int i, const unsigned short vZ) {
+		nuclearZ_[getNucleusRef(i)] = vZ;
+	}
+
+	void setNucleusRef(const unsigned int i, const int v) {
+		nucleusRef_[i] = v;
+	}
+
+	int getNuclearA(const unsigned int i) const {
+		return nuclearA_[getNucleusRef(i)];
+	}
+
+	int getNuclearZ(const unsigned int i) const {
+		return nuclearZ_[getNucleusRef(i)];
+	}
+	// this function will create new storage for Nuclear Properties, and return the
+			// reference to it
+	int getNucleusNextRef() {
+		nuclearA_.push_back(0);
+		nuclearZ_.push_back(0);
+		return nuclearA_.size() - 1;
+	}
+
+	int getNucleusRef(const unsigned int i) const {
+		if (nucleusRef_[i] >= 0) return nucleusRef_[i];
+		std::ostringstream err;
+		err << "NuclearStackExtension: no nucleus at ref=" << i;
+		throw std::runtime_error(err.str());
+	}
+
+	bool isNucleus(const unsigned int i) const { return nucleusRef_[i] >= 0; }
+
+	/**
+	 *   Function to copy particle at location i1 in stack to i2
+	 */
+	void copy(const unsigned int i1, const unsigned int i2) {
+		// index range check
+		if (i1 >= getSize() || i2 >= getSize()) {
+			std::ostringstream err;
+			err << "NuclearStackExtension: trying to access data beyond size of stack!";
+			throw std::runtime_error(err.str());
+		}
+		// copy internal particle data p[i2] = p[i1]
+		super_type::copy(i1, i2);
+		// check if any of p[i1] or p[i2] was a Code::Nucleus
+		const int ref1 = nucleusRef_[i1];
+		const int ref2 = nucleusRef_[i2];
+		if (ref2 < 0) {
+			if (ref1 >= 0) {
+				// i1 is nucleus, i2 is not
+				nucleusRef_[i2] = getNucleusNextRef();
+				nuclearA_[nucleusRef_[i2]] = nuclearA_[ref1];
+				nuclearZ_[nucleusRef_[i2]] = nuclearZ_[ref1];
+			} else {
+				// neither i1 nor i2 are nuclei
+			}
+		} else {
+			if (ref1 >= 0) {
+				// both are nuclei, i2 is overwritten with nucleus i1
+				// fNucleusRef stays the same, but A and Z data is overwritten
+				nuclearA_[ref2] = nuclearA_[ref1];
+				nuclearZ_[ref2] = nuclearZ_[ref1];
+			} else {
+				// i2 is overwritten with non-nucleus i1
+				nucleusRef_[i2] = -1;                       // flag as non-nucleus
+				nuclearA_.erase(nuclearA_.cbegin() + ref2); // remove data for i2
+				nuclearZ_.erase(nuclearZ_.cbegin() + ref2); // remove data for i2
+				const int n = nucleusRef_.size(); // update fNucleusRef: indices above ref2
+				// must be decremented by 1
+				for (int i = 0; i < n; ++i) {
+					if (nucleusRef_[i] > ref2) { nucleusRef_[i] -= 1; }
+				}
+			}
+		}
+	}
+
+	/**
+	 *   Function to copy particle at location i2 in stack to i1
+	 */
+	void swap(const unsigned int i1, const unsigned int i2) {
+		// index range check
+		if (i1 >= getSize() || i2 >= getSize()) {
+			std::ostringstream err;
+			err << "NuclearStackExtension: trying to access data beyond size of stack!";
+			throw std::runtime_error(err.str());
+		}
+		// swap original particle data
+		super_type::swap(i1, i2);
+		// swap corresponding nuclear reference data
+		std::swap(nucleusRef_[i2], nucleusRef_[i1]);
+	}
+
+	void incrementSize() {
+		super_type::incrementSize();
+		nucleusRef_.push_back(-1);
+	}
+
+	void decrementSize() {
+		super_type::decrementSize();
+		if (nucleusRef_.size() > 0) {
+			const int ref = nucleusRef_.back();
+			nucleusRef_.pop_back();
+			if (ref >= 0) {
+				nuclearA_.erase(nuclearA_.begin() + ref);
+				nuclearZ_.erase(nuclearZ_.begin() + ref);
+				const int n = nucleusRef_.size();
+				for (int i = 0; i < n; ++i) {
+					if (nucleusRef_[i] >= ref) { nucleusRef_[i] -= 1; }
+				}
+			}
+		}
+	}
+
+private:
+	/// the actual memory to store particle data
+
+	nucleus_ref_type nucleusRef_;
+	nuclear_a_type     nuclearA_;
+	nuclear_z_type     nuclearZ_;
+
+}; // end class NuclearStackExtensionImpl
+
+template <typename InnerStack, template <typename> typename _PI>
+using NuclearStackExtension =
+		Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, _PI> ;
+
+//
+template <typename StackIter>
+using ExtendedParticleInterfaceType = NuclearParticleInterface<SuperStupidStack, StackIter>;
+
+// the particle data stack with extra nuclear information:
+using ParticleDataStack = NuclearStackExtension<SuperStupidStack, ExtendedParticleInterfaceType>;
+
+
 } // namespace corsika
diff --git a/corsika/stack/SuperStupidStack.hpp b/corsika/stack/SuperStupidStack.hpp
index 267f172dd6b90937152179e4ebebad6bbcf8d1a4..34251a82be64b1fb29354590b69b398326637d4a 100644
--- a/corsika/stack/SuperStupidStack.hpp
+++ b/corsika/stack/SuperStupidStack.hpp
@@ -22,224 +22,259 @@
 
 namespace corsika {
 
-  typedef corsika::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
-
-  namespace super_stupid {
-
-    /**
-     * Example of a particle object on the stack.
-     */
-
-    template <typename StackIteratorInterface>
-    class ParticleInterface : public ParticleBase<StackIteratorInterface> {
-
-    protected:
-      using corsika::ParticleBase<StackIteratorInterface>::GetStack;
-      using corsika::ParticleBase<StackIteratorInterface>::GetStackData;
-
-    public:
-      using corsika::ParticleBase<StackIteratorInterface>::GetIndex;
-
-    public:
-      std::string as_string() const {
-        using namespace corsika::units::si;
-        return fmt::format("particle: i={}, PID={}, E={}GeV", GetIndex(),
-                           particles::GetName(GetPID()), GetEnergy() / 1_GeV);
-      }
-
-      void SetParticleData(
-          const std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                           MomentumVector, corsika::Point, corsika::units::si::TimeType>&
-              v) {
-        SetPID(std::get<0>(v));
-        SetEnergy(std::get<1>(v));
-        SetMomentum(std::get<2>(v));
-        SetPosition(std::get<3>(v));
-        SetTime(std::get<4>(v));
-      }
-      /*
-    void SetParticleData(const corsika::Code vDataPID,
-                         const corsika::units::si::HEPEnergyType vDataE,
-                         const MomentumVector& vMomentum,
-                         const corsika::Point& vPosition,
-                         const corsika::units::si::TimeType vTime) {
-      }*/
-
-      void SetParticleData(
-          ParticleInterface<StackIteratorInterface>&,
-          const std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                           MomentumVector, corsika::Point, corsika::units::si::TimeType>&
-              v) {
-        SetPID(std::get<0>(v));
-        SetEnergy(std::get<1>(v));
-        SetMomentum(std::get<2>(v));
-        SetPosition(std::get<3>(v));
-        SetTime(std::get<4>(v));
-      }
-      /*      void SetParticleData(ParticleInterface<StackIteratorInterface>&,
-                           const corsika::Code vDataPID,
-                           const corsika::units::si::HEPEnergyType vDataE,
-                           const MomentumVector& vMomentum,
-                           const corsika::Point& vPosition,
-                           const corsika::units::si::TimeType vTime) {
-        SetPID(vDataPID);
-        SetEnergy(vDataE);
-        SetMomentum(vMomentum);
-        SetPosition(vPosition);
-        SetTime(vTime);
-      }*/
-
-      /// individual setters
-      void SetPID(const corsika::Code id) { GetStackData().SetPID(GetIndex(), id); }
-      void SetEnergy(const corsika::units::si::HEPEnergyType& e) {
-        GetStackData().SetEnergy(GetIndex(), e);
-      }
-      void SetMomentum(const MomentumVector& v) {
-        GetStackData().SetMomentum(GetIndex(), v);
-      }
-      void SetPosition(const corsika::Point& v) {
-        GetStackData().SetPosition(GetIndex(), v);
-      }
-      void SetTime(const corsika::units::si::TimeType& v) {
-        GetStackData().SetTime(GetIndex(), v);
-      }
-
-      /// individual getters
-      corsika::Code GetPID() const { return GetStackData().GetPID(GetIndex()); }
-      corsika::units::si::HEPEnergyType GetEnergy() const {
-        return GetStackData().GetEnergy(GetIndex());
-      }
-      MomentumVector GetMomentum() const {
-        return GetStackData().GetMomentum(GetIndex());
-      }
-      corsika::Point GetPosition() const {
-        return GetStackData().GetPosition(GetIndex());
-      }
-      corsika::units::si::TimeType GetTime() const {
-        return GetStackData().GetTime(GetIndex());
-      }
-      /**
-       * @name derived quantities
-       *
-       * @{
-       */
-      corsika::Vector<corsika::units::si::dimensionless_d> GetDirection() const {
-        return GetMomentum() / GetEnergy();
-      }
-      corsika::units::si::HEPMassType GetMass() const {
-        return corsika::GetMass(GetPID());
-      }
-      int16_t GetChargeNumber() const { return corsika::GetChargeNumber(GetPID()); }
-      ///@}
-    };
-
-    /**
-     * Memory implementation of the most simple (stupid) particle stack object.
-     */
-
-    class SuperStupidStackImpl {
-
-    public:
-      void Init() {}
-      void Dump() const {}
-
-      void Clear() {
-        fDataPID.clear();
-        fDataE.clear();
-        fMomentum.clear();
-        fPosition.clear();
-        fTime.clear();
-      }
-
-      unsigned int GetSize() const { return fDataPID.size(); }
-      unsigned int GetCapacity() const { return fDataPID.size(); }
-
-      void SetPID(const unsigned int i, const corsika::Code id) { fDataPID[i] = id; }
-      void SetEnergy(const unsigned int i, const corsika::units::si::HEPEnergyType e) {
-        fDataE[i] = e;
-      }
-      void SetMomentum(const unsigned int i, const MomentumVector& v) {
-        fMomentum[i] = v;
-      }
-      void SetPosition(const unsigned int i, const corsika::Point& v) {
-        fPosition[i] = v;
-      }
-      void SetTime(const unsigned int i, const corsika::units::si::TimeType& v) {
-        fTime[i] = v;
-      }
-
-      corsika::Code GetPID(const unsigned int i) const { return fDataPID[i]; }
-      corsika::units::si::HEPEnergyType GetEnergy(const unsigned int i) const {
-        return fDataE[i];
-      }
-      MomentumVector GetMomentum(const unsigned int i) const { return fMomentum[i]; }
-      corsika::Point GetPosition(const unsigned int i) const { return fPosition[i]; }
-      corsika::units::si::TimeType GetTime(const unsigned int i) const {
-        return fTime[i];
-      }
-
-      /**
-       *   Function to copy particle at location i2 in stack to i1
-       */
-      void Copy(const unsigned int i1, const unsigned int i2) {
-        fDataPID[i2] = fDataPID[i1];
-        fDataE[i2] = fDataE[i1];
-        fMomentum[i2] = fMomentum[i1];
-        fPosition[i2] = fPosition[i1];
-        fTime[i2] = fTime[i1];
-      }
-
-      /**
-       *   Function to copy particle at location i2 in stack to i1
-       */
-      void Swap(const unsigned int i1, const unsigned int i2) {
-        std::swap(fDataPID[i2], fDataPID[i1]);
-        std::swap(fDataE[i2], fDataE[i1]);
-        std::swap(fMomentum[i2], fMomentum[i1]);
-        std::swap(fPosition[i2], fPosition[i1]);
-        std::swap(fTime[i2], fTime[i1]);
-      }
-
-      void IncrementSize() {
-        using corsika::Code;
-        using corsika::Point;
-        fDataPID.push_back(Code::Unknown);
-        fDataE.push_back(0 * corsika::units::si::electronvolt);
-        CoordinateSystem& dummyCS =
-            RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
-        fMomentum.push_back(MomentumVector(
-            dummyCS,
-            {0 * corsika::units::si::electronvolt, 0 * corsika::units::si::electronvolt,
-             0 * corsika::units::si::electronvolt}));
-        fPosition.push_back(
-            Point(dummyCS, {0 * corsika::units::si::meter, 0 * corsika::units::si::meter,
-                            0 * corsika::units::si::meter}));
-        fTime.push_back(0 * corsika::units::si::second);
-      }
-
-      void DecrementSize() {
-        if (fDataE.size() > 0) {
-          fDataPID.pop_back();
-          fDataE.pop_back();
-          fMomentum.pop_back();
-          fPosition.pop_back();
-          fTime.pop_back();
-        }
-      }
-
-    private:
-      /// the actual memory to store particle data
-
-      std::vector<corsika::Code> fDataPID;
-      std::vector<corsika::units::si::HEPEnergyType> fDataE;
-      std::vector<MomentumVector> fMomentum;
-      std::vector<corsika::Point> fPosition;
-      std::vector<corsika::units::si::TimeType> fTime;
-
-    }; // end class SuperStupidStackImpl
-
-    typedef Stack<SuperStupidStackImpl, ParticleInterface> SuperStupidStack;
-
-  } // namespace super_stupid
+
+/**
+ * Example of a particle object on the stack.
+ */
+
+template <typename StackIteratorInterface>
+struct ParticleInterface : public ParticleBase<StackIteratorInterface> {
+
+private:
+
+	typedef corsika::ParticleBase<StackIteratorInterface> super_type;
+
+public:
+
+	typedef corsika::Vector<corsika::units::si::hepmomentum_d> momentum_vector_type;
+
+	std::string as_string() const {
+		using namespace corsika::units::si;
+		return fmt::format("particle: i={}, PID={}, E={}GeV", super_type::GetIndex(),
+				particles::GetName(this->getPID()), this->getEnergy() / 1_GeV);
+	}
+
+	void setParticleData( std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
+			momentum_vector_type, corsika::Point, corsika::units::si::TimeType> const& v) {
+		this->setPID(std::get<0>(v));
+		this->setEnergy(std::get<1>(v));
+		this->setMomentum(std::get<2>(v));
+		this->setPosition(std::get<3>(v));
+		this->setTime(std::get<4>(v));
+	}
+
+	void setParticleData( ParticleInterface<StackIteratorInterface> const&,
+			std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
+			momentum_vector_type, corsika::Point, corsika::units::si::TimeType> const& v) {
+		this->setPID(std::get<0>(v));
+		this->setEnergy(std::get<1>(v));
+		this->setMomentum(std::get<2>(v));
+		this->setPosition(std::get<3>(v));
+		this->setTime(std::get<4>(v));
+	}
+
+	/// individual setters
+	void setPID(const corsika::Code id) {
+		super_type::GetStackData().setPID(super_type::GetIndex(), id);
+	}
+	void setEnergy(const corsika::units::si::HEPEnergyType& e) {
+		super_type::GetStackData().setEnergy(super_type::GetIndex(), e);
+	}
+	void setMomentum(const momentum_vector_type& v) {
+		super_type::GetStackData().setMomentum(super_type::GetIndex(), v);
+	}
+	void setPosition(const corsika::Point& v) {
+		super_type::GetStackData().setPosition(super_type::GetIndex(), v);
+	}
+	void setTime(const corsika::units::si::TimeType& v) {
+		super_type::GetStackData().setTime(super_type::GetIndex(), v);
+	}
+
+	/// individual getters
+	corsika::Code getPID() const {
+		return super_type::GetStackData().getPID(super_type::GetIndex());
+	}
+	corsika::units::si::HEPEnergyType getEnergy() const {
+		return super_type::GetStackData().getEnergy(super_type::GetIndex());
+	}
+	momentum_vector_type getMomentum() const {
+		return super_type::GetStackData().getMomentum(super_type::GetIndex());
+	}
+	corsika::Point getPosition() const {
+		return super_type::GetStackData().getPosition(super_type::GetIndex());
+	}
+	corsika::units::si::TimeType getTime() const {
+		return super_type::GetStackData().getTime(super_type::GetIndex());
+	}
+	/**
+	 * @name derived quantities
+	 *
+	 * @{
+	 */
+	corsika::Vector<corsika::units::si::dimensionless_d> getDirection() const {
+		return  this->getMomentum() /  this->getEnergy();
+	}
+
+	corsika::units::si::HEPMassType getMass() const {
+		return corsika::GetMass(this->getPID());
+	}
+
+	int16_t getChargeNumber() const {
+		return corsika::GetChargeNumber(this->getPID());
+	}
+	///@}
+};
+
+/**
+ * Memory implementation of the most simple (stupid) particle stack object.
+ *
+ */
+
+class SuperStupidStackImpl {
+
+public:
+
+	typedef  corsika::Vector<corsika::units::si::hepmomentum_d>        momentum_type;
+	typedef  std::vector<corsika::Code>                             code_vector_type;
+	typedef  std::vector<corsika::units::si::HEPEnergyType>       energy_vector_type;
+	typedef  std::vector<corsika::Point>                           point_vector_type;
+	typedef  std::vector<corsika::units::si::TimeType>              time_vector_type;
+	typedef  std::vector<momentum_type>                         momentum_vector_type;
+
+	SuperStupidStackImpl()=default;
+
+	SuperStupidStackImpl( SuperStupidStackImpl const& other)=default;
+
+	SuperStupidStackImpl( SuperStupidStackImpl && other)=default;
+
+
+	SuperStupidStackImpl& operator=( SuperStupidStackImpl const& other)=default;
+
+	SuperStupidStackImpl& operator=( SuperStupidStackImpl && other)=default;
+
+
+	void init() {}
+	void dump() const {}
+
+	void clear() {
+		dataPID_.clear();
+		dataE_.clear();
+		momentum_.clear();
+		position_.clear();
+		time_.clear();
+	}
+
+	unsigned int getSize() const { return dataPID_.size(); }
+	unsigned int getCapacity() const { return dataPID_.size(); }
+
+	void setPID(size_t i, const corsika::Code id) {
+		dataPID_[i] = id;
+	}
+	void setEnergy(size_t i,  corsika::units::si::HEPEnergyType  const& e) {
+		dataE_[i] = e;
+	}
+	void setMomentum(size_t i, momentum_type const& v) {
+		momentum_[i] = v;
+	}
+	void setPosition(size_t i, corsika::Point const& v) {
+		position_[i] = v;
+	}
+	void setTime(size_t i, corsika::units::si::TimeType const& v) {
+		time_[i] = v;
+	}
+
+	corsika::Code getPID(size_t i) const {
+		return dataPID_[i];
+	}
+
+	corsika::units::si::HEPEnergyType getEnergy(size_t i) const {
+		return dataE_[i];
+	}
+
+	momentum_type getMomentum(size_t i) const {
+		return momentum_[i];
+	}
+
+	corsika::Point getPosition(size_t i) const {
+		return position_[i];
+	}
+	corsika::units::si::TimeType getTime(size_t i) const {
+		return time_[i];
+	}
+
+	corsika::units::si::HEPEnergyType getDataE(size_t i) const {
+		return dataE_[i];
+	}
+
+	void setDataE(size_t i, corsika::units::si::HEPEnergyType const& dataE) {
+		dataE_[i] = dataE;
+	}
+
+	corsika::Code getDataPid(size_t i) const {
+		return dataPID_;
+	}
+
+	void setDataPid(size_t i, corsika::Code  const& dataPid) {
+		dataPID_[i] = dataPid;
+	}
+	/**
+	 *   Function to copy particle at location i2 in stack to i1
+	 */
+	 void copy(size_t i1, size_t i2) {
+		dataPID_[i2]  = dataPID_[i1];
+		dataE_[i2]    = dataE_[i1];
+		momentum_[i2] = momentum_[i1];
+		position_[i2] = position_[i1];
+		time_[i2]     = time_[i1];
+	 }
+
+
+	 /**
+	  *   FIXME: change to iterators.
+	  *   Function to copy particle at location i2 in stack to i1
+	  */
+	 void swap(size_t i1, size_t i2) {
+		 std::swap(dataPID_[i2] , dataPID_[i1]);
+		 std::swap(dataE_[i2]   , dataE_[i1]);
+		 std::swap(momentum_[i2], momentum_[i1]);
+		 std::swap(position_[i2], position_[i1]);
+		 std::swap(time_[i2]    , time_[i1]);
+	 }
+
+	 void incrementSize() {
+		 using corsika::Point;
+		 using corsika::Code;
+
+		 dataPID_.push_back(Code::Unknown);
+		 dataE_.push_back(0 * corsika::units::si::electronvolt);
+
+		 CoordinateSystem& dummyCS = RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
+
+		 momentum_.push_back(momentum_type( dummyCS,
+				 {0 * corsika::units::si::electronvolt, 0 * corsika::units::si::electronvolt,
+						 0 * corsika::units::si::electronvolt}));
+
+		 position_.push_back(
+				 Point(dummyCS, {0 * corsika::units::si::meter, 0 * corsika::units::si::meter,
+						 0 * corsika::units::si::meter}));
+		 time_.push_back(0 * corsika::units::si::second);
+	 }
+
+	 void decrementSize() {
+		 if (dataE_.size() > 0) {
+			 dataPID_.pop_back();
+			 dataE_.pop_back();
+			 momentum_.pop_back();
+			 position_.pop_back();
+			 time_.pop_back();
+		 }
+	 }
+
+
+private:
+
+	 /// the actual memory to store particle data
+	 code_vector_type dataPID_;
+	 energy_vector_type dataE_;
+	 momentum_vector_type momentum_;
+	 point_vector_type position_;
+	 time_vector_type time_;
+
+}; // end class SuperStupidStackImpl
+
+
+typedef Stack<SuperStupidStackImpl, ParticleInterface> SuperStupidStack;
+
 
 } // namespace corsika
+
diff --git a/dependencies/qgsjetII/qgsjet-II-04.cc b/dependencies/qgsjetII/qgsjet-II-04.cc
deleted file mode 100644
index 7bb93c1a471c2c5a887b1672abc1107059c5ceaf..0000000000000000000000000000000000000000
--- a/dependencies/qgsjetII/qgsjet-II-04.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * This software is distributed under the terms of the GNU General Public
- * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
- * the license.
- */
-
-#include <qgsjet-II-04.h>
-
-//#include <corsika/framework/random/RNGManager.hpp>
-
-#include <iostream>
-#include <random>
-
-datadir::datadir(const std::string& dir) {
-  if (dir.length() > 130) {
-    std::cerr << "QGSJetII error, will cut datadir \"" << dir
-              << "\" to 130 characters: " << std::endl;
-  }
-  int i = 0;
-  for (i = 0; i < std::min(130, int(dir.length())); ++i) data[i] = dir[i];
-  data[i + 0] = ' ';
-  data[i + 1] = '\0';
-}
-
-double qgran_(int&) {
-  // static corsika::random::RNG& rng =
-  //  corsika::random::RNGManager::GetInstance().GetRandomStream("qgsjet");
-
-  //  std::uniform_real_distribution<double> dist;
-  return 0; // dist(rng);
-}
diff --git a/dependencies/sibyll/rndm_dbl.f b/dependencies/sibyll/rndm_dbl.f
deleted file mode 100644
index 42db719788f480150f95c2a68d73cc706647586c..0000000000000000000000000000000000000000
--- a/dependencies/sibyll/rndm_dbl.f
+++ /dev/null
@@ -1,416 +0,0 @@
-C***********************************************************************
-C
-C    interface to PHOJET double precision random number generator 
-C    for SIBYLL \FR'14
-C
-C***********************************************************************
-      DOUBLE PRECISION FUNCTION S_RNDM(IDUMMY)
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      DUMMY = dble(IDUMMY)
-      S_RNDM= PHO_RNDM(DUMMY)
-      END
-
-C***********************************************************************
-C
-C    initialization routine for double precision random number generator
-C    calls PHO_RNDIN \FR'14
-C
-C***********************************************************************
-      SUBROUTINE RND_INI
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      COMMON /RNDMGAS/ ISET
-      ISET = 0
-      CALL PHO_RNDIN(12,34,56,78)
-      END
-
-
-      DOUBLE PRECISION FUNCTION GASDEV(Idum)
-C***********************************************************************
-C     Gaussian deviation
-C***********************************************************************
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      IMPLICIT INTEGER(I-N)
-      COMMON /RNDMGAS/ ISET
-      SAVE
-      DATA ISET/0/      
-      gasdev=idum
-      IF (ISET.EQ.0) THEN
-1       V1=2.D0*S_RNDM(0)-1.D0
-        V2=2.D0*S_RNDM(1)-1.D0
-        R=V1**2+V2**2
-        IF(R.GE.1.D0)GO TO 1
-        FAC=SQRT(-2.D0*LOG(R)/R)
-        GSET=V1*FAC
-        GASDEV=V2*FAC
-        ISET=1
-      ELSE
-        GASDEV=GSET
-        ISET=0
-      ENDIF
-      RETURN
-      END
-C***********************************************************************
-      
-
-      DOUBLE PRECISION FUNCTION PHO_RNDM(DUMMY)
-C***********************************************************************
-C
-C    random number generator
-C
-C    initialization by call to PHO_RNDIN needed!
-C     
-C    the algorithm is taken from
-C      G.Marsaglia, A.Zaman: 'Toward a unversal random number generator'
-C      Florida State Univ. preprint FSU-SCRI-87-70
-C
-C    implementation by K. Hahn (Dec. 88), changed to include possibility
-C    of saving / reading generator registers to / from file (R.E. 10/98)
-C
-C    generator should not depend on the hardware (if a real has
-C    at least 24 significant bits in internal representation),
-C    the period is about 2**144,
-C
-C    internal registers:
-C       U(97),C,CD,CM,I,J  - seed values as initialized in PHO_RNDIN
-C
-C
-C***********************************************************************
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      SAVE
-
-      COMMON /PORAND/ U(97),C,CD,CM,I,J
-
- 100  CONTINUE
-      RNDMI = DUMMY
-      RNDMI = U(I)-U(J)
-      IF ( RNDMI.LT.0.D0 ) RNDMI = RNDMI+1.D0
-      U(I) = RNDMI
-      I    = I-1
-      IF ( I.EQ.0 ) I = 97
-      J    = J-1
-      IF ( J.EQ.0 ) J = 97
-      C    = C-CD
-      IF ( C.LT.0.D0 ) C = C+CM
-      RNDMI = RNDMI-C
-      IF ( RNDMI.LT.0.D0 ) RNDMI = RNDMI+1.D0
-
-      IF((ABS(RNDMI).LT.0.D0).OR.(ABS(RNDMI-1.D0).LT.1.D-10)) GOTO 100
-      PHO_RNDM = RNDMI
-
-      END
-
-
-CDECK  ID>, PHO_RNDIN
-      SUBROUTINE PHO_RNDIN(NA1,NA2,NA3,NB1)
-C***********************************************************************
-C
-C     initialization of PHO_RNDM, has to be called before using PHO_RNDM
-C
-C     input:
-C       NA1,NA2,NA3,NB1  - values for initializing the generator
-C                          NA? must be in 1..178 and not all 1;
-C                          12,34,56  are the standard values
-C                          NB1 must be in 1..168;
-C                          78  is the standard value
-C
-C***********************************************************************
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      SAVE
-
-      COMMON /PORAND/ U(97),C,CD,CM,I,J
-      MA1 = NA1
-      MA2 = NA2
-      MA3 = NA3
-      MB1 = NB1
-      I   = 97
-      J   = 33
-      DO 20 II2 = 1,97
-        S = 0.D0
-        T = 0.5D0
-        DO 10 II1 = 1,24
-          MAT  = MOD(MOD(MA1*MA2,179)*MA3,179)
-          MA1  = MA2
-          MA2  = MA3
-          MA3  = MAT
-          MB1  = MOD(53*MB1+1,169)
-          IF ( MOD(MB1*MAT,64).GE.32 ) S = S+T
-          T    = 0.5D0*T
- 10     CONTINUE
-        U(II2) = S
- 20   CONTINUE
-      C  =   362436.D0/16777216.D0
-      CD =  7654321.D0/16777216.D0
-      CM = 16777213.D0/16777216.D0
-
-      END
-
-
-CDECK  ID>, PHO_RNDSI
-      SUBROUTINE PHO_RNDSI(UIN,CIN,CDIN,CMIN,IIN,JIN)
-C***********************************************************************
-C
-C     updates internal random number generator registers using
-C     registers given as arguments
-C
-C***********************************************************************
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      SAVE
-
-      DIMENSION UIN(97)
-      COMMON /PORAND/ U(97),C,CD,CM,I,J
-      DO 10 KKK = 1,97
-        U(KKK) = UIN(KKK)
- 10   CONTINUE
-      C  = CIN
-      CD = CDIN
-      CM = CMIN
-      I  = IIN
-      J  = JIN
-
-      END
-
-
-CDECK  ID>, PHO_RNDSO
-      SUBROUTINE PHO_RNDSO(UOUT,COUT,CDOUT,CMOUT,IOUT,JOUT)
-C***********************************************************************
-C
-C     copies internal registers from randon number generator
-C     to arguments
-C
-C***********************************************************************
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      SAVE
-
-      DIMENSION UOUT(97)
-      COMMON /PORAND/ U(97),C,CD,CM,I,J
-      DO 10 KKK = 1,97
-        UOUT(KKK) = U(KKK)
- 10   CONTINUE
-      COUT  = C
-      CDOUT = CD
-      CMOUT = CM
-      IOUT  = I
-      JOUT  = J
-
-      END
-
-
-CDECK  ID>, PHO_RNDTE
-      SUBROUTINE PHO_RNDTE(IO)
-C***********************************************************************
-C
-C     test of random number generator PHO_RNDM
-C
-C     input:
-C       IO defines output
-C           0  output only if an error is detected
-C           1  output independend on an error
-C
-C     uses PHO_RNDSI and PHO_RNDSO to bring the random number generator
-C     to same status as it had before the test run
-C
-C***********************************************************************
-      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
-      SAVE
-
-
-C  input/output channels
-      INTEGER LI,LO
-      COMMON /POINOU/ LI,LO
-
-      DIMENSION UU(97)
-      DIMENSION U(6),X(6),D(6)
-      DATA U / 6533892.D0 , 14220222.D0 ,  7275067.D0 ,
-     &         6172232.D0 ,  8354498.D0 , 10633180.D0 /
-
-      CALL PHO_RNDSO(UU,CC,CCD,CCM,II,JJ)
-
-      CALL PHO_RNDIN(12,34,56,78)
-      DO 10 II1 = 1,20000
-        XX      = PHO_RNDM(SD)
- 10   CONTINUE
-
-      SD        = 0.D0
-      DO 20 II2 = 1,6
-        X(II2)  = 4096.D0*(4096.D0*PHO_RNDM(XX))
-        D(II2)  = X(II2)-U(II2)
-        SD      = SD+ABS(D(II2))
- 20   CONTINUE
-
-      CALL PHO_RNDSI(UU,CC,CCD,CCM,II,JJ)
-
-      IF ((IO.EQ.1).OR.(ABS(SD).GT.0.D-10)) THEN
-        WRITE(LO,50) (U(I),X(I),D(I),I=1,6)
-      ENDIF
-
- 50   FORMAT(/,' PHO_RNDTE: test of the random number generator:',/,
-     &  '    expected value    calculated value     difference',/,
-     &  6(F17.1,F20.1,F15.3,/),
-     &  ' generator has the same status as before calling PHO_RNDTE',/)
-
-      END
-
-
-CDECK  ID>, PHO_RNDST
-      SUBROUTINE PHO_RNDST(MODE,FILENA)
-C***********************************************************************
-C
-C     read / write random number generator status from / to file
-C
-C     input:    MODE        1   read registers from file
-C                           2   dump registers to file
-C
-C               FILENA      file name
-C
-C***********************************************************************
-
-      IMPLICIT NONE
-
-
-
-      SAVE
-
-      INTEGER       MODE
-      CHARACTER*(*) FILENA
-
-
-C  input/output channels
-      INTEGER LI,LO
-      COMMON /POINOU/ LI,LO
-
-
-      DOUBLE PRECISION UU,CC,CCD,CCM
-      DIMENSION UU(97)
-
-      INTEGER I,II,JJ
-
-      CHARACTER*80 CH_DUMMY
-
-      IF(MODE.EQ.1) THEN
-
-        WRITE(LO,'(/,1X,2A,A,/)') 'PHO_RNDST: ',
-     &    'reading random number registers from file ',FILENA
-
-        OPEN(12,FILE=FILENA,ERR=1010,STATUS='OLD')
-        READ(12,*,ERR=1010) CH_DUMMY
-        DO I=1,97
-          READ(12,*,ERR=1010) UU(I)
-        ENDDO
-        READ(12,*,ERR=1010) CC
-        READ(12,*,ERR=1010) CCD
-        READ(12,*,ERR=1010) CCM
-        READ(12,*,ERR=1010) II,JJ
-        CLOSE(12)
-        CALL PHO_RNDSI(UU,CC,CCD,CCM,II,JJ)
-
-      ELSE IF(MODE.EQ.2) THEN
-
-        WRITE(LO,'(/,1X,2A,A,/)') 'PHO_RNDST: ',
-     &    'dumping random number registers to file ',FILENA
-
-        OPEN(12,FILE=FILENA,ERR=1010,STATUS='UNKNOWN')
-        CALL PHO_RNDSO(UU,CC,CCD,CCM,II,JJ)
-        WRITE(12,'(1X,A)',ERR=1020) 'random number status registers:'
-        DO I=1,97
-          WRITE(12,'(1X,1P,E28.20)',ERR=1020) UU(I)
-        ENDDO
-        WRITE(12,'(1X,1P,E28.20)',ERR=1020) CC
-        WRITE(12,'(1X,1P,E28.20)',ERR=1020) CCD
-        WRITE(12,'(1X,1P,E28.20)',ERR=1020) CCM
-        WRITE(12,'(1X,2I4)',ERR=1020) II,JJ
-        CLOSE(12)
-
-      ELSE
-
-        WRITE(LO,'(/,1X,2A,I6,/)') 'PHO_RNDST: ',
-     &    'called with invalid mode, nothing done (mode)',MODE
-
-      ENDIF
-
-      RETURN
-
- 1010 CONTINUE
-      WRITE(LO,'(1X,2A,A,/)') 'PHO_RNDST: ',
-     &  'cannot open or read file ',FILENA
-      RETURN
-
- 1020 CONTINUE
-      WRITE(LO,'(1X,A,A,/)') 'PHO_RNDST: ',
-     &  'cannot open or write file ',FILENA
-      RETURN
-    
-      END
-
-C----------------------------------------
-C standard generator
-C----------------------------------------
-      REAL FUNCTION S_RNDM_std(IDUMMY)
-C...Generator  from the LUND montecarlo
-C...Purpose: to generate random numbers uniformly distributed between
-C...0 and 1, excluding the endpoints.
-      COMMON/LUDATR/MRLU(6),RRLU(100)
-      SAVE /LUDATR/
-      EQUIVALENCE (MRLU1,MRLU(1)),(MRLU2,MRLU(2)),(MRLU3,MRLU(3)),
-     &(MRLU4,MRLU(4)),(MRLU5,MRLU(5)),(MRLU6,MRLU(6)),
-     &(RRLU98,RRLU(98)),(RRLU99,RRLU(99)),(RRLU00,RRLU(100))
- 
-C...  Initialize generation from given seed.
-      S_RNDM_std = real(idummy)
-      IF(MRLU2.EQ.0) THEN
-        IF (MRLU1 .EQ. 0)  MRLU1 = 19780503    ! initial seed
-        IJ=MOD(MRLU1/30082,31329)
-        KL=MOD(MRLU1,30082)
-        I=MOD(IJ/177,177)+2
-        J=MOD(IJ,177)+2
-        K=MOD(KL/169,178)+1
-        L=MOD(KL,169)
-        DO 110 II=1,97
-        S=0.
-        T=0.5
-        DO 100 JJ=1,24
-        M=MOD(MOD(I*J,179)*K,179)
-        I=J
-        J=K
-        K=M
-        L=MOD(53*L+1,169)
-        IF(MOD(L*M,64).GE.32) S=S+T
-        T=0.5*T
-  100   CONTINUE
-        RRLU(II)=S
-  110   CONTINUE
-        TWOM24=1.
-        DO 120 I24=1,24
-        TWOM24=0.5*TWOM24
-  120   CONTINUE
-        RRLU98=362436.*TWOM24
-        RRLU99=7654321.*TWOM24
-        RRLU00=16777213.*TWOM24
-        MRLU2=1
-        MRLU3=0
-        MRLU4=97
-        MRLU5=33
-      ENDIF
- 
-C...Generate next random number.
-  130 RUNI=RRLU(MRLU4)-RRLU(MRLU5)
-      IF(RUNI.LT.0.) RUNI=RUNI+1.
-      RRLU(MRLU4)=RUNI
-      MRLU4=MRLU4-1
-      IF(MRLU4.EQ.0) MRLU4=97
-      MRLU5=MRLU5-1
-      IF(MRLU5.EQ.0) MRLU5=97
-      RRLU98=RRLU98-RRLU99
-      IF(RRLU98.LT.0.) RRLU98=RRLU98+RRLU00
-      RUNI=RUNI-RRLU98
-      IF(RUNI.LT.0.) RUNI=RUNI+1.
-      IF(RUNI.LE.0.OR.RUNI.GE.1.) GOTO 130
- 
-C...Update counters. Random number to output.
-      MRLU3=MRLU3+1
-      IF(MRLU3.EQ.1000000000) THEN
-        MRLU2=MRLU2+1
-        MRLU3=0
-      ENDIF
-      S_RNDM_std=RUNI
-
-      END
diff --git a/do-clang-format.py b/do-clang-format.py
index c31f9dde45b87dd69d2303735d480415278f219c..10a04073eb50cd23fa69b29ba63ed87dbe389b9c 100755
--- a/do-clang-format.py
+++ b/do-clang-format.py
@@ -17,15 +17,18 @@ parser.add_argument("--all", action="store_true",
 
 args = parser.parse_args()
 
+excludeDirs = ["./modules", "./externals", "build", "install", "git"]
+
 filelist = []
 if args.all:
     for dirpath, dirnames, filenames in os.walk("."):
         excl = False
-        excl_dirs = ["ThirdParty", "build", "externals"]
-        for excl_dir in excl_dirs:
+        for excl_dir in excludeDirs:
             if excl_dir in dirpath:
                 excl = True
-        if excl: continue
+                break
+        if excl:
+            continue
         for f in filenames:
             if f.endswith(".hpp") or f.endswith(".cpp"):
                 filename = os.path.join(dirpath, f)
@@ -46,7 +49,9 @@ else:
     cmd = "git ls-files --exclude-standard --others"
     filelist += subp.check_output(cmd, shell=True).decode("utf8").strip().split("\n")
     filelist = [x for x in filelist
-                if "ThirdParty" not in x and (x.endswith(".h") or x.endswith(".cc"))]
+                if "./externals" not in x and
+                   "./modules" not in x and
+                   (x.endswith(".hpp") or x.endswith(".cpp"))]
 
 cmd = "clang-format"
 if "CLANG_FORMAT" in os.environ:
@@ -55,6 +60,7 @@ cmd +=  " -style=file"
 if args.apply:
     for filename in filelist:
         subp.check_call(cmd.split() + ["-i", filename])
+
 else:
     # only print files which need formatting
     files_need_formatting = 0
diff --git a/do-copyright.py b/do-copyright.py
index ec10db429fa32692688f43208b78e4403c6afaf7..e550f303e577860c369145152194238f2ddf5240 100755
--- a/do-copyright.py
+++ b/do-copyright.py
@@ -21,8 +21,8 @@ Debug settings are 0: nothing, 1: checking, 2: filesystem
 """
 Debug = 0 
 
-excludeDirs = ["ThirdParty", "externals", "dependencies", "git"]
-excludeFiles = ['PhysicalConstants.h','CorsikaFenvOSX.cc', 'sgn.h']
+excludeDirs = ["./modules", "./externals", "build", "install", "git"]
+excludeFiles = ['PhysicalConstants.h','CorsikaFenvOSX.cc', 'sgn.h', 'quartic.h']
 
 extensions = [".cpp", ".hpp"]
 
@@ -194,7 +194,7 @@ def next_file(dir_name, files, justCheck, forYear, updateMessage):
     for check in excludeDirs :
         if check in dir_name:
             if Debug>1:
-                print ("exclude-dir: " + check)
+                print ("exclude-dir: " + check, dir_name)
             return True
     for check in files :
         if (os.path.isdir(check)):
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 029679c9847386ccef17eaa63964bc309d57f144..6b47de1c8e607a184c10e0ed6ba28255ae70cd84 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,30 +1,40 @@
 add_executable (helix_example helix_example.cpp)
 target_link_libraries (helix_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (helix_example)
 
 add_executable (geometry_example geometry_example.cpp)
 target_link_libraries (geometry_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (geometry_example)
 
-# loggin back in March was not used
+# logging back in March was not used
 #add_executable (logger_example logger_example.cpp)
 #target_link_libraries (logger_example CORSIKA8)
+#CORSIKA_REGISTER_EXAMPLE (logger_example)
 
 add_executable (stack_example stack_example.cpp)
 target_link_libraries (stack_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (stack_example)
 
 add_executable (cascade_example cascade_example.cpp)
 target_link_libraries (cascade_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (cascade_example)
 
 add_executable (boundary_example boundary_example.cpp)
 target_link_libraries (boundary_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (boundary_example)
 
 add_executable (cascade_proton_example cascade_proton_example.cpp)
 target_link_libraries (cascade_proton_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (cascade_proton_example)
 
 add_executable (vertical_EAS vertical_EAS.cpp)
 target_link_libraries (vertical_EAS CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (vertical_EAS)
 
 add_executable (stopping_power stopping_power.cpp)
 target_link_libraries (stopping_power CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (stopping_power)
 
 add_executable (staticsequence_example staticsequence_example.cpp)
 target_link_libraries (staticsequence_example CORSIKA8)
+CORSIKA_REGISTER_EXAMPLE (staticsequence_example)
diff --git a/examples/boundary_example.cpp b/examples/boundary_example.cpp
index 7c708abd244ed4a98cecc4bd5eae84f1defad18b..2096ddce4b68b03d29d41ae9051b95e979b50717 100644
--- a/examples/boundary_example.cpp
+++ b/examples/boundary_example.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -10,10 +8,9 @@
 
 #include <corsika/framework/core/Cascade.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-
 #include <corsika/framework/geometry/Sphere.hpp>
+#include <corsika/framework/process/ProcessSequence.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/ProcessSequence.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 
 #include <corsika/setup/SetupEnvironment.hpp>
@@ -24,12 +21,10 @@
 #include <corsika/media/HomogeneousMedium.hpp>
 #include <corsika/media/NuclearComposition.hpp>
 
-#include <corsika/modules/particle_cut/ParticleCut.hpp>
-#include <corsika/modules/sibyll/Decay.hpp>
-#include <corsika/modules/sibyll/Interaction.hpp>
-#include <corsika/modules/sibyll/NuclearInteraction.hpp>
-#include <corsika/modules/track_writer/TrackWriter.hpp>
-#include <corsika/modules/tracking_line/TrackingLine.hpp>
+#include <corsika/modules/ParticleCut.hpp>
+#include <corsika/modules/Sibyll.hpp>
+#include <corsika/modules/TrackWriter.hpp>
+#include <corsika/modules/TrackingLine.hpp>
 
 #include <iostream>
 #include <limits>
diff --git a/examples/cascade_example.cpp b/examples/cascade_example.cpp
index d5f0bb76063cb1459e1832ce37f9e968dca8951d..41233a03df708227de8e96d00cfb5cfd159abed4 100644
--- a/examples/cascade_example.cpp
+++ b/examples/cascade_example.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -12,17 +10,15 @@
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Sphere.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/ProcessSequence.hpp>
+#include <corsika/framework/process/ProcessSequence.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 
-#include <corsika/modules/energy_loss/EnergyLoss.hpp>
-#include <corsika/modules/particle_cut/ParticleCut.hpp>
-#include <corsika/modules/sibyll/Decay.hpp>
-#include <corsika/modules/sibyll/Interaction.hpp>
-#include <corsika/modules/sibyll/NuclearInteraction.hpp>
-#include <corsika/modules/stack_inspector/StackInspector.hpp>
-#include <corsika/modules/track_writer/TrackWriter.hpp>
-#include <corsika/modules/tracking_line/TrackingLine.hpp>
+#include <corsika/modules/BetheBlochPDG.hpp>
+#include <corsika/modules/ParticleCut.hpp>
+#include <corsika/modules/Sibyll.hpp>
+#include <corsika/modules/StackInspector.hpp>
+#include <corsika/modules/TrackWriter.hpp>
+#include <corsika/modules/TrackingLine.hpp>
 
 #include <corsika/setup/SetupEnvironment.hpp>
 #include <corsika/setup/SetupStack.hpp>
@@ -36,7 +32,6 @@
 #include <limits>
 
 using namespace corsika;
-using namespace corsika::units::si;
 using namespace corsika::setup;
 using namespace std;
 
@@ -111,8 +106,8 @@ int main() {
     cout << "input angles: theta=" << theta << " phi=" << phi << endl;
     cout << "input momentum: " << plab.GetComponents() / 1_GeV << endl;
     stack.AddParticle(
-        std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                   corsika::Point, units::si::TimeType, unsigned short, unsigned short>{
+        std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector, corsika::Point,
+                   TimeType, unsigned short, unsigned short>{
             beamCode, E0, plab, injectionPos, 0_ns, nuclA, nuclZ});
   }
 
@@ -129,7 +124,7 @@ int main() {
   corsika::particle_cut::ParticleCut cut(80_GeV);
 
   corsika::track_writer::TrackWriter trackWriter("tracks.dat");
-  corsika::energy_loss::EnergyLoss eLoss(
+  corsika::energy_loss::BetheBlochPDG eLoss(
       injectionPos, corsika::Vector<dimensionless_d>(rootCS, {0, 0, -1}));
 
   // assemble all processes into an ordered process list
diff --git a/examples/cascade_proton_example.cpp b/examples/cascade_proton_example.cpp
index c325f2b4187da266f30cbb46ed1cc6798a16216d..56ad016399ae1c0f6e6132c83d3c4040c80af28b 100644
--- a/examples/cascade_proton_example.cpp
+++ b/examples/cascade_proton_example.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -12,19 +10,16 @@
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Sphere.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/ProcessSequence.hpp>
+#include <corsika/framework/process/ProcessSequence.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 
-#include <corsika/modules/energy_loss/EnergyLoss.hpp>
-#include <corsika/modules/particle_cut/ParticleCut.hpp>
-#include <corsika/modules/pythia8/Decay.hpp>
-#include <corsika/modules/pythia8/Interaction.hpp>
-#include <corsika/modules/sibyll/Decay.hpp>
-#include <corsika/modules/sibyll/Interaction.hpp>
-#include <corsika/modules/sibyll/NuclearInteraction.hpp>
-#include <corsika/modules/stack_inspector/StackInspector.hpp>
-#include <corsika/modules/track_writer/TrackWriter.hpp>
-#include <corsika/modules/tracking_line/TrackingLine.hpp>
+#include <corsika/modules/BetheBlochPDG.hpp>
+#include <corsika/modules/ParticleCut.hpp>
+#include <corsika/modules/Pythia8.hpp>
+#include <corsika/modules/Sibyll.hpp>
+#include <corsika/modules/StackInspector.hpp>
+#include <corsika/modules/TrackWriter.hpp>
+#include <corsika/modules/TrackingLine.hpp>
 
 #include <corsika/setup/SetupEnvironment.hpp>
 #include <corsika/setup/SetupStack.hpp>
diff --git a/examples/geometry_example.cpp b/examples/geometry_example.cpp
index 0c44131367a4350e1bb7f4977ab39ca1901a29b5..e2d7e284f941e83905f90f69a44b4ed5c8072926 100644
--- a/examples/geometry_example.cpp
+++ b/examples/geometry_example.cpp
@@ -1,5 +1,5 @@
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+n/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/examples/helix_example.cpp b/examples/helix_example.cpp
index e79d9a205e5d0e004e3cc10d027a69df13b23f46..357e791afbe57610a3abeb700453a9aa1bfdd0fa 100644
--- a/examples/helix_example.cpp
+++ b/examples/helix_example.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/examples/logger_example.cpp b/examples/logger_example.cpp
index ce53b3a67aac4a85d8bc2d21ae63a5aba8f2f0d8..3270277c3db799febd270492a7d1715014b70d75 100644
--- a/examples/logger_example.cpp
+++ b/examples/logger_example.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/examples/stack_example.cpp b/examples/stack_example.cpp
index 6b32945c9a3a6833cac6ee2d6682b1eb3151a54a..bee9dd3674df07d82a754453a2d1591bc395cf60 100644
--- a/examples/stack_example.cpp
+++ b/examples/stack_example.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -37,10 +37,11 @@ void read(corsika::super_stupid::SuperStupidStack& s) {
   assert(s.GetSize() == 11); // stack has 11 particles
 
   HEPEnergyType total_energy;
-  for (auto& p : s) {
+  int i = 0;
+  for (const auto& p : s) {
     total_energy += p.GetEnergy();
     // particles are electrons with 1.5 GeV energy times i
-    assert(p.GetPID() == particles::Code::Electron);
+    assert(p.GetPID() == corsika::Code::Electron);
     assert(p.GetEnergy() == 1.5_GeV * (i++));
   }
 }
diff --git a/examples/staticsequence_example.cpp b/examples/staticsequence_example.cpp
index 8458bdd7b37908bd587feeda4324ce6966f32394..44caf418b363f35176e5c38b6a49b00c1a885a7d 100644
--- a/examples/staticsequence_example.cpp
+++ b/examples/staticsequence_example.cpp
@@ -1,12 +1,12 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
-#include <corsika/framework/sequence/ProcessSequence.hpp>
+#include <corsika/framework/process/ProcessSequence.hpp>
 
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/RootCoordinateSystem.hpp>
diff --git a/examples/stopping_power.cpp b/examples/stopping_power.cpp
index 746e98416522d9afe29bf92972da4b7167e3e951..f2e034d3d0ce911585ed7f6424295db8a17f5b12 100644
--- a/examples/stopping_power.cpp
+++ b/examples/stopping_power.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -14,7 +12,7 @@
 #include <corsika/framework/geometry/Sphere.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 
-#include <corsika/modules/energy_loss/EnergyLoss.hpp>
+#include <corsika/modules/BetheBlochPDG.hpp>
 
 #include <corsika/setup/SetupStack.hpp>
 
@@ -44,7 +42,7 @@ int main() {
 
   Vector<dimensionless_d> showerAxis(rootCS, {0, 0, -1});
 
-  corsika::energy_loss::EnergyLoss eLoss(injectionPos, showerAxis);
+  corsika::energy_loss::BetheBlochPDG eLoss(injectionPos, showerAxis);
 
   setup::Stack stack;
 
diff --git a/examples/vertical_EAS.cpp b/examples/vertical_EAS.cpp
index 85b5c30dbf63d6f66e974c26c023e76562b7bb0d..c4c9bf52c7ba6cc7ba087af4ec0b512e4405ff61 100644
--- a/examples/vertical_EAS.cpp
+++ b/examples/vertical_EAS.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -12,9 +10,9 @@
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Plane.hpp>
 #include <corsika/framework/geometry/Sphere.hpp>
+#include <corsika/framework/process/ProcessSequence.hpp>
+#include <corsika/framework/process/StackProcess.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
-#include <corsika/framework/sequence/ProcessSequence.hpp>
-#include <corsika/framework/sequence/StackProcess.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 
 #include <corsika/setup/SetupStack.hpp>
@@ -25,16 +23,14 @@
 #include <corsika/media/LayeredSphericalAtmosphereBuilder.hpp>
 #include <corsika/media/NuclearComposition.hpp>
 
-#include <corsika/modules/energy_loss/EnergyLoss.hpp>
-#include <corsika/modules/observation_plane/ObservationPlane.hpp>
-#include <corsika/modules/particle_cut/ParticleCut.hpp>
-#include <corsika/modules/sibyll/Decay.hpp>
-#include <corsika/modules/sibyll/Interaction.hpp>
-#include <corsika/modules/sibyll/NuclearInteraction.hpp>
-#include <corsika/modules/switch_process/SwitchProcess.hpp>
-#include <corsika/modules/track_writer/TrackWriter.hpp>
-#include <corsika/modules/tracking_line/TrackingLine.hpp>
-#include <corsika/modules/urqmd/UrQMD.hpp>
+#include <corsika/modules/BetheBlochPDG.hpp>
+#include <corsika/modules/ObservationPlane.hpp>
+#include <corsika/modules/ParticleCut.hpp>
+#include <corsika/modules/Sibyll.hpp>
+#include <corsika/modules/SwitchProcess.hpp>
+#include <corsika/modules/TrackWriter.hpp>
+#include <corsika/modules/TrackingLine.hpp>
+#include <corsika/modules/UrQMD.hpp>
 
 #include <iomanip>
 #include <iostream>
@@ -43,7 +39,6 @@
 
 using namespace corsika;
 using namespace corsika::setup;
-using namespace corsika::units::si;
 using namespace std;
 
 void registerRandomStreams() {
@@ -109,9 +104,8 @@ int main() {
   std::cout << "input momentum: " << plab.GetComponents() / 1_GeV << std::endl;
 
   stack.AddParticle(
-      std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                 corsika::Point, units::si::TimeType>{beamCode, E0, plab, injectionPos,
-                                                      0_ns});
+      std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector, corsika::Point,
+                 TimeType>{beamCode, E0, plab, injectionPos, 0_ns});
   //  }
 
   Line const line(injectionPos, plab.normalized() * 1_m * 1_Hz);
@@ -130,7 +124,7 @@ int main() {
   corsika::particle_cut::ParticleCut cut(5_GeV);
 
   corsika::track_writer::TrackWriter trackWriter("tracks.dat");
-  corsika::energy_loss::EnergyLoss eLoss(showerAxis);
+  corsika::energy_loss::BetheBlochPDG eLoss(showerAxis);
 
   Plane const obsPlane(Point(rootCS, 0_m, 0_m, observationHeight),
                        Vector<dimensionless_d>(rootCS, {0., 0., 1.}));
diff --git a/externals/cnpy/CMakeLists.txt b/externals/cnpy/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4a115728d660361d0159c1c309efdabb332b51c3
--- /dev/null
+++ b/externals/cnpy/CMakeLists.txt
@@ -0,0 +1,45 @@
+set (
+  CNPY_SOURCES
+  cnpy.cpp
+  )
+
+set (
+  CNPY_HEADERS
+  cnpy.hpp
+  )
+
+set (
+  CNPY_NAMESPACE
+  corsika/third_party/cnpy
+  )
+
+add_library (cnpy STATIC ${CNPY_SOURCES})
+CORSIKA_COPY_HEADERS_TO_NAMESPACE (cnpy ${CNPY_NAMESPACE} ${CNPY_HEADERS})
+
+set_target_properties (
+  cnpy
+  PROPERTIES
+  VERSION ${PROJECT_VERSION}
+  SOVERSION 1
+  )
+
+# target dependencies on other libraries (also the header onlys)
+target_link_libraries (
+  cnpy
+  PUBLIC
+  ZLIB::ZLIB
+  )
+
+target_include_directories (
+  cnpy 
+  INTERFACE 
+  $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
+  $<INSTALL_INTERFACE:include/include>
+  )
+
+install (
+  TARGETS cnpy
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+  )
+
diff --git a/externals/cnpy/cnpy.cpp b/externals/cnpy/cnpy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..026afcd55bf22a05790fd29c9225bb7f9324d403
--- /dev/null
+++ b/externals/cnpy/cnpy.cpp
@@ -0,0 +1,342 @@
+// Copyright (C) 2011  Carl Rogers
+// Released under MIT License
+// license available in LICENSE file, or at
+// http://www.opensource.org/licenses/mit-license.php
+
+#include "cnpy.hpp"
+#include <complex>
+#include <cstdlib>
+#include <algorithm>
+#include <cstring>
+#include <iomanip>
+#include <stdint.h>
+#include <stdexcept>
+#include <regex>
+
+char cnpy::BigEndianTest() {
+  int x = 1;
+  return (((char*)&x)[0]) ? '<' : '>';
+}
+
+char cnpy::map_type(const std::type_info& t) {
+  if (t == typeid(float)) return 'f';
+  if (t == typeid(double)) return 'f';
+  if (t == typeid(long double)) return 'f';
+
+  if (t == typeid(int)) return 'i';
+  if (t == typeid(char)) return 'i';
+  if (t == typeid(short)) return 'i';
+  if (t == typeid(long)) return 'i';
+  if (t == typeid(long long)) return 'i';
+
+  if (t == typeid(unsigned char)) return 'u';
+  if (t == typeid(unsigned short)) return 'u';
+  if (t == typeid(unsigned long)) return 'u';
+  if (t == typeid(unsigned long long)) return 'u';
+  if (t == typeid(unsigned int)) return 'u';
+
+  if (t == typeid(bool)) return 'b';
+
+  if (t == typeid(std::complex<float>)) return 'c';
+  if (t == typeid(std::complex<double>)) return 'c';
+  if (t == typeid(std::complex<long double>))
+    return 'c';
+
+  else
+    return '?';
+}
+
+template <>
+std::vector<char>& cnpy::operator+=(std::vector<char>& lhs, const std::string rhs) {
+  lhs.insert(lhs.end(), rhs.begin(), rhs.end());
+  return lhs;
+}
+
+template <>
+std::vector<char>& cnpy::operator+=(std::vector<char>& lhs, const char* rhs) {
+  // write in little endian
+  size_t len = strlen(rhs);
+  lhs.reserve(len);
+  for (size_t byte = 0; byte < len; byte++) { lhs.push_back(rhs[byte]); }
+  return lhs;
+}
+
+void cnpy::parse_npy_header(unsigned char* buffer, size_t& word_size,
+                            std::vector<size_t>& shape, bool& fortran_order) {
+  // std::string magic_string(buffer,6);
+  uint8_t major_version = *reinterpret_cast<uint8_t*>(buffer + 6);
+  uint8_t minor_version = *reinterpret_cast<uint8_t*>(buffer + 7);
+  uint16_t header_len = *reinterpret_cast<uint16_t*>(buffer + 8);
+  std::string header(reinterpret_cast<char*>(buffer + 9), header_len);
+
+  size_t loc1, loc2;
+
+  // fortran order
+  loc1 = header.find("fortran_order") + 16;
+  fortran_order = (header.substr(loc1, 4) == "True" ? true : false);
+
+  // shape
+  loc1 = header.find("(");
+  loc2 = header.find(")");
+
+  std::regex num_regex("[0-9][0-9]*");
+  std::smatch sm;
+  shape.clear();
+
+  std::string str_shape = header.substr(loc1 + 1, loc2 - loc1 - 1);
+  while (std::regex_search(str_shape, sm, num_regex)) {
+    shape.push_back(std::stoi(sm[0].str()));
+    str_shape = sm.suffix().str();
+  }
+
+  // endian, word size, data type
+  // byte order code | stands for not applicable.
+  // not sure when this applies except for byte array
+  loc1 = header.find("descr") + 9;
+  bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false);
+  assert(littleEndian);
+
+  // char type = header[loc1+1];
+  // assert(type == map_type(T));
+
+  std::string str_ws = header.substr(loc1 + 2);
+  loc2 = str_ws.find("'");
+  word_size = atoi(str_ws.substr(0, loc2).c_str());
+}
+
+void cnpy::parse_npy_header(FILE* fp, size_t& word_size, std::vector<size_t>& shape,
+                            bool& fortran_order) {
+  char buffer[256];
+  size_t res = fread(buffer, sizeof(char), 11, fp);
+  if (res != 11) throw std::runtime_error("parse_npy_header: failed fread");
+  std::string header = fgets(buffer, 256, fp);
+  assert(header[header.size() - 1] == '\n');
+
+  size_t loc1, loc2;
+
+  // fortran order
+  loc1 = header.find("fortran_order");
+  if (loc1 == std::string::npos)
+    throw std::runtime_error(
+        "parse_npy_header: failed to find header keyword: 'fortran_order'");
+  loc1 += 16;
+  fortran_order = (header.substr(loc1, 4) == "True" ? true : false);
+
+  // shape
+  loc1 = header.find("(");
+  loc2 = header.find(")");
+  if (loc1 == std::string::npos || loc2 == std::string::npos)
+    throw std::runtime_error(
+        "parse_npy_header: failed to find header keyword: '(' or ')'");
+
+  std::regex num_regex("[0-9][0-9]*");
+  std::smatch sm;
+  shape.clear();
+
+  std::string str_shape = header.substr(loc1 + 1, loc2 - loc1 - 1);
+  while (std::regex_search(str_shape, sm, num_regex)) {
+    shape.push_back(std::stoi(sm[0].str()));
+    str_shape = sm.suffix().str();
+  }
+
+  // endian, word size, data type
+  // byte order code | stands for not applicable.
+  // not sure when this applies except for byte array
+  loc1 = header.find("descr");
+  if (loc1 == std::string::npos)
+    throw std::runtime_error("parse_npy_header: failed to find header keyword: 'descr'");
+  loc1 += 9;
+  bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false);
+  assert(littleEndian);
+
+  // char type = header[loc1+1];
+  // assert(type == map_type(T));
+
+  std::string str_ws = header.substr(loc1 + 2);
+  loc2 = str_ws.find("'");
+  word_size = atoi(str_ws.substr(0, loc2).c_str());
+}
+
+void cnpy::parse_zip_footer(FILE* fp, uint16_t& nrecs, size_t& global_header_size,
+                            size_t& global_header_offset) {
+  std::vector<char> footer(22);
+  fseek(fp, -22, SEEK_END);
+  size_t res = fread(&footer[0], sizeof(char), 22, fp);
+  if (res != 22) throw std::runtime_error("parse_zip_footer: failed fread");
+
+  uint16_t disk_no, disk_start, nrecs_on_disk, comment_len;
+  disk_no = *(uint16_t*)&footer[4];
+  disk_start = *(uint16_t*)&footer[6];
+  nrecs_on_disk = *(uint16_t*)&footer[8];
+  nrecs = *(uint16_t*)&footer[10];
+  global_header_size = *(uint32_t*)&footer[12];
+  global_header_offset = *(uint32_t*)&footer[16];
+  comment_len = *(uint16_t*)&footer[20];
+
+  assert(disk_no == 0);
+  assert(disk_start == 0);
+  assert(nrecs_on_disk == nrecs);
+  assert(comment_len == 0);
+}
+
+cnpy::NpyArray load_the_npy_file(FILE* fp) {
+  std::vector<size_t> shape;
+  size_t word_size;
+  bool fortran_order;
+  cnpy::parse_npy_header(fp, word_size, shape, fortran_order);
+
+  cnpy::NpyArray arr(shape, word_size, fortran_order);
+  size_t nread = fread(arr.data<char>(), 1, arr.num_bytes(), fp);
+  if (nread != arr.num_bytes())
+    throw std::runtime_error("load_the_npy_file: failed fread");
+  return arr;
+}
+
+cnpy::NpyArray load_the_npz_array(FILE* fp, uint32_t compr_bytes,
+                                  uint32_t uncompr_bytes) {
+
+  std::vector<unsigned char> buffer_compr(compr_bytes);
+  std::vector<unsigned char> buffer_uncompr(uncompr_bytes);
+  size_t nread = fread(&buffer_compr[0], 1, compr_bytes, fp);
+  if (nread != compr_bytes) throw std::runtime_error("load_the_npy_file: failed fread");
+
+  int err;
+  z_stream d_stream;
+
+  d_stream.zalloc = Z_NULL;
+  d_stream.zfree = Z_NULL;
+  d_stream.opaque = Z_NULL;
+  d_stream.avail_in = 0;
+  d_stream.next_in = Z_NULL;
+  err = inflateInit2(&d_stream, -MAX_WBITS);
+
+  d_stream.avail_in = compr_bytes;
+  d_stream.next_in = &buffer_compr[0];
+  d_stream.avail_out = uncompr_bytes;
+  d_stream.next_out = &buffer_uncompr[0];
+
+  err = inflate(&d_stream, Z_FINISH);
+  err = inflateEnd(&d_stream);
+
+  std::vector<size_t> shape;
+  size_t word_size;
+  bool fortran_order;
+  cnpy::parse_npy_header(&buffer_uncompr[0], word_size, shape, fortran_order);
+
+  cnpy::NpyArray array(shape, word_size, fortran_order);
+
+  size_t offset = uncompr_bytes - array.num_bytes();
+  memcpy(array.data<unsigned char>(), &buffer_uncompr[0] + offset, array.num_bytes());
+
+  return array;
+}
+
+cnpy::npz_t cnpy::npz_load(std::string fname) {
+  FILE* fp = fopen(fname.c_str(), "rb");
+
+  if (!fp) {
+    throw std::runtime_error("npz_load: Error! Unable to open file " + fname + "!");
+  }
+
+  cnpy::npz_t arrays;
+
+  while (1) {
+    std::vector<char> local_header(30);
+    size_t headerres = fread(&local_header[0], sizeof(char), 30, fp);
+    if (headerres != 30) throw std::runtime_error("npz_load: failed fread");
+
+    // if we've reached the global header, stop reading
+    if (local_header[2] != 0x03 || local_header[3] != 0x04) break;
+
+    // read in the variable name
+    uint16_t name_len = *(uint16_t*)&local_header[26];
+    std::string varname(name_len, ' ');
+    size_t vname_res = fread(&varname[0], sizeof(char), name_len, fp);
+    if (vname_res != name_len) throw std::runtime_error("npz_load: failed fread");
+
+    // erase the lagging .npy
+    varname.erase(varname.end() - 4, varname.end());
+
+    // read in the extra field
+    uint16_t extra_field_len = *(uint16_t*)&local_header[28];
+    if (extra_field_len > 0) {
+      std::vector<char> buff(extra_field_len);
+      size_t efield_res = fread(&buff[0], sizeof(char), extra_field_len, fp);
+      if (efield_res != extra_field_len)
+        throw std::runtime_error("npz_load: failed fread");
+    }
+
+    uint16_t compr_method = *reinterpret_cast<uint16_t*>(&local_header[0] + 8);
+    uint32_t compr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0] + 18);
+    uint32_t uncompr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0] + 22);
+
+    if (compr_method == 0) {
+      arrays[varname] = load_the_npy_file(fp);
+    } else {
+      arrays[varname] = load_the_npz_array(fp, compr_bytes, uncompr_bytes);
+    }
+  }
+
+  fclose(fp);
+  return arrays;
+}
+
+cnpy::NpyArray cnpy::npz_load(std::string fname, std::string varname) {
+  FILE* fp = fopen(fname.c_str(), "rb");
+
+  if (!fp) throw std::runtime_error("npz_load: Unable to open file " + fname);
+
+  while (1) {
+    std::vector<char> local_header(30);
+    size_t header_res = fread(&local_header[0], sizeof(char), 30, fp);
+    if (header_res != 30) throw std::runtime_error("npz_load: failed fread");
+
+    // if we've reached the global header, stop reading
+    if (local_header[2] != 0x03 || local_header[3] != 0x04) break;
+
+    // read in the variable name
+    uint16_t name_len = *(uint16_t*)&local_header[26];
+    std::string vname(name_len, ' ');
+    size_t vname_res = fread(&vname[0], sizeof(char), name_len, fp);
+    if (vname_res != name_len) throw std::runtime_error("npz_load: failed fread");
+    vname.erase(vname.end() - 4, vname.end()); // erase the lagging .npy
+
+    // read in the extra field
+    uint16_t extra_field_len = *(uint16_t*)&local_header[28];
+    fseek(fp, extra_field_len, SEEK_CUR); // skip past the extra field
+
+    uint16_t compr_method = *reinterpret_cast<uint16_t*>(&local_header[0] + 8);
+    uint32_t compr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0] + 18);
+    uint32_t uncompr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0] + 22);
+
+    if (vname == varname) {
+      NpyArray array = (compr_method == 0)
+                           ? load_the_npy_file(fp)
+                           : load_the_npz_array(fp, compr_bytes, uncompr_bytes);
+      fclose(fp);
+      return array;
+    } else {
+      // skip past the data
+      uint32_t size = *(uint32_t*)&local_header[22];
+      fseek(fp, size, SEEK_CUR);
+    }
+  }
+
+  fclose(fp);
+
+  // if we get here, we haven't found the variable in the file
+  throw std::runtime_error("npz_load: Variable name " + varname + " not found in " +
+                           fname);
+}
+
+cnpy::NpyArray cnpy::npy_load(std::string fname) {
+
+  FILE* fp = fopen(fname.c_str(), "rb");
+
+  if (!fp) throw std::runtime_error("npy_load: Unable to open file " + fname);
+
+  NpyArray arr = load_the_npy_file(fp);
+
+  fclose(fp);
+  return arr;
+}
diff --git a/externals/cnpy/cnpy.hpp b/externals/cnpy/cnpy.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..51668d3280d12fa84414b56beeee2088f308f567
--- /dev/null
+++ b/externals/cnpy/cnpy.hpp
@@ -0,0 +1,294 @@
+// Copyright (C) 2011  Carl Rogers
+// Released under MIT License
+// license available in LICENSE file, or at
+// http://www.opensource.org/licenses/mit-license.php
+
+#pragma once
+
+#include <string>
+#include <stdexcept>
+#include <sstream>
+#include <vector>
+#include <cstdio>
+#include <typeinfo>
+#include <iostream>
+#include <cassert>
+#include <zlib.h>
+#include <map>
+#include <memory>
+#include <stdint.h>
+#include <numeric>
+
+namespace cnpy {
+
+  struct NpyArray {
+    NpyArray(const std::vector<size_t>& _shape, size_t _word_size, bool _fortran_order)
+        : shape(_shape)
+        , word_size(_word_size)
+        , fortran_order(_fortran_order) {
+      num_vals = 1;
+      for (size_t i = 0; i < shape.size(); i++) num_vals *= shape[i];
+      data_holder =
+          std::shared_ptr<std::vector<char>>(new std::vector<char>(num_vals * word_size));
+    }
+
+    NpyArray()
+        : shape(0)
+        , word_size(0)
+        , fortran_order(0)
+        , num_vals(0) {}
+
+    template <typename T>
+    T* data() {
+      return reinterpret_cast<T*>(&(*data_holder)[0]);
+    }
+
+    template <typename T>
+    const T* data() const {
+      return reinterpret_cast<T*>(&(*data_holder)[0]);
+    }
+
+    template <typename T>
+    std::vector<T> as_vec() const {
+      const T* p = data<T>();
+      return std::vector<T>(p, p + num_vals);
+    }
+
+    size_t num_bytes() const { return data_holder->size(); }
+
+    std::shared_ptr<std::vector<char>> data_holder;
+    std::vector<size_t> shape;
+    size_t word_size;
+    bool fortran_order;
+    size_t num_vals;
+  };
+
+  using npz_t = std::map<std::string, NpyArray>;
+
+  char BigEndianTest();
+  char map_type(const std::type_info& t);
+  template <typename T>
+  std::vector<char> create_npy_header(const std::vector<size_t>& shape);
+  void parse_npy_header(FILE* fp, size_t& word_size, std::vector<size_t>& shape,
+                        bool& fortran_order);
+  void parse_npy_header(unsigned char* buffer, size_t& word_size,
+                        std::vector<size_t>& shape, bool& fortran_order);
+  void parse_zip_footer(FILE* fp, uint16_t& nrecs, size_t& global_header_size,
+                        size_t& global_header_offset);
+  npz_t npz_load(std::string fname);
+  NpyArray npz_load(std::string fname, std::string varname);
+  NpyArray npy_load(std::string fname);
+
+  template <typename T>
+  std::vector<char>& operator+=(std::vector<char>& lhs, const T rhs) {
+    // write in little endian
+    for (size_t byte = 0; byte < sizeof(T); byte++) {
+      char val = *((char*)&rhs + byte);
+      lhs.push_back(val);
+    }
+    return lhs;
+  }
+
+  template <>
+  std::vector<char>& operator+=(std::vector<char>& lhs, const std::string rhs);
+  template <>
+  std::vector<char>& operator+=(std::vector<char>& lhs, const char* rhs);
+
+  template <typename T>
+  void npy_save(std::string fname, const T* data, const std::vector<size_t> shape,
+                std::string mode = "w") {
+    FILE* fp = NULL;
+    std::vector<size_t> true_data_shape; // if appending, the shape of existing + new data
+
+    if (mode == "a") fp = fopen(fname.c_str(), "r+b");
+
+    if (fp) {
+      // file exists. we need to append to it. read the header, modify the array size
+      size_t word_size;
+      bool fortran_order;
+      parse_npy_header(fp, word_size, true_data_shape, fortran_order);
+      assert(!fortran_order);
+
+      if (word_size != sizeof(T)) {
+        std::cout << "libnpy error: " << fname << " has word size " << word_size
+                  << " but npy_save appending data sized " << sizeof(T) << "\n";
+        assert(word_size == sizeof(T));
+      }
+      if (true_data_shape.size() != shape.size()) {
+        std::cout << "libnpy error: npy_save attempting to append misdimensioned data to "
+                  << fname << "\n";
+        assert(true_data_shape.size() != shape.size());
+      }
+
+      for (size_t i = 1; i < shape.size(); i++) {
+        if (shape[i] != true_data_shape[i]) {
+          std::cout << "libnpy error: npy_save attempting to append misshaped data to "
+                    << fname << "\n";
+          assert(shape[i] == true_data_shape[i]);
+        }
+      }
+      true_data_shape[0] += shape[0];
+    } else {
+      fp = fopen(fname.c_str(), "wb");
+      true_data_shape = shape;
+    }
+
+    std::vector<char> header = create_npy_header<T>(true_data_shape);
+    size_t nels =
+        std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>());
+
+    fseek(fp, 0, SEEK_SET);
+    fwrite(&header[0], sizeof(char), header.size(), fp);
+    fseek(fp, 0, SEEK_END);
+    fwrite(data, sizeof(T), nels, fp);
+    fclose(fp);
+  }
+
+  template <typename T>
+  void npz_save(std::string zipname, std::string fname, const T* data,
+                const std::vector<size_t>& shape, std::string mode = "w") {
+    // first, append a .npy to the fname
+    fname += ".npy";
+
+    // now, on with the show
+    FILE* fp = NULL;
+    uint16_t nrecs = 0;
+    size_t global_header_offset = 0;
+    std::vector<char> global_header;
+
+    if (mode == "a") fp = fopen(zipname.c_str(), "r+b");
+
+    if (fp) {
+      // zip file exists. we need to add a new npy file to it.
+      // first read the footer. this gives us the offset and size of the global header
+      // then read and store the global header.
+      // below, we will write the the new data at the start of the global header then
+      // append the global header and footer below it
+      size_t global_header_size;
+      parse_zip_footer(fp, nrecs, global_header_size, global_header_offset);
+      fseek(fp, global_header_offset, SEEK_SET);
+      global_header.resize(global_header_size);
+      size_t res = fread(&global_header[0], sizeof(char), global_header_size, fp);
+      if (res != global_header_size) {
+        throw std::runtime_error(
+            "npz_save: header read error while adding to existing zip");
+      }
+      fseek(fp, global_header_offset, SEEK_SET);
+    } else {
+      fp = fopen(zipname.c_str(), "wb");
+    }
+
+    std::vector<char> npy_header = create_npy_header<T>(shape);
+
+    size_t nels =
+        std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>());
+    size_t nbytes = nels * sizeof(T) + npy_header.size();
+
+    // get the CRC of the data to be added
+    uint32_t crc = crc32(0L, (uint8_t*)&npy_header[0], npy_header.size());
+    crc = crc32(crc, (uint8_t*)data, nels * sizeof(T));
+
+    // build the local header
+    std::vector<char> local_header;
+    local_header += "PK";                   // first part of sig
+    local_header += (uint16_t)0x0403;       // second part of sig
+    local_header += (uint16_t)20;           // min version to extract
+    local_header += (uint16_t)0;            // general purpose bit flag
+    local_header += (uint16_t)0;            // compression method
+    local_header += (uint16_t)0;            // file last mod time
+    local_header += (uint16_t)0;            // file last mod date
+    local_header += (uint32_t)crc;          // crc
+    local_header += (uint32_t)nbytes;       // compressed size
+    local_header += (uint32_t)nbytes;       // uncompressed size
+    local_header += (uint16_t)fname.size(); // fname length
+    local_header += (uint16_t)0;            // extra field length
+    local_header += fname;
+
+    // build global header
+    global_header += "PK";             // first part of sig
+    global_header += (uint16_t)0x0201; // second part of sig
+    global_header += (uint16_t)20;     // version made by
+    global_header.insert(global_header.end(), local_header.begin() + 4,
+                         local_header.begin() + 30);
+    global_header += (uint16_t)0; // file comment length
+    global_header += (uint16_t)0; // disk number where file starts
+    global_header += (uint16_t)0; // internal file attributes
+    global_header += (uint32_t)0; // external file attributes
+    global_header +=
+        (uint32_t)global_header_offset; // relative offset of local file header, since it
+                                        // begins where the global header used to begin
+    global_header += fname;
+
+    // build footer
+    std::vector<char> footer;
+    footer += "PK";                           // first part of sig
+    footer += (uint16_t)0x0605;               // second part of sig
+    footer += (uint16_t)0;                    // number of this disk
+    footer += (uint16_t)0;                    // disk where footer starts
+    footer += (uint16_t)(nrecs + 1);          // number of records on this disk
+    footer += (uint16_t)(nrecs + 1);          // total number of records
+    footer += (uint32_t)global_header.size(); // nbytes of global headers
+    footer += (uint32_t)(
+        global_header_offset + nbytes +
+        local_header.size()); // offset of start of global headers, since global header
+                              // now starts after newly written array
+    footer += (uint16_t)0; // zip file comment length
+
+    // write everything
+    fwrite(&local_header[0], sizeof(char), local_header.size(), fp);
+    fwrite(&npy_header[0], sizeof(char), npy_header.size(), fp);
+    fwrite(data, sizeof(T), nels, fp);
+    fwrite(&global_header[0], sizeof(char), global_header.size(), fp);
+    fwrite(&footer[0], sizeof(char), footer.size(), fp);
+    fclose(fp);
+  }
+
+  template <typename T>
+  void npy_save(std::string fname, const std::vector<T> data, std::string mode = "w") {
+    std::vector<size_t> shape;
+    shape.push_back(data.size());
+    npy_save(fname, &data[0], shape, mode);
+  }
+
+  template <typename T>
+  void npz_save(std::string zipname, std::string fname, const std::vector<T> data,
+                std::string mode = "w") {
+    std::vector<size_t> shape;
+    shape.push_back(data.size());
+    npz_save(zipname, fname, &data[0], shape, mode);
+  }
+
+  template <typename T>
+  std::vector<char> create_npy_header(const std::vector<size_t>& shape) {
+
+    std::vector<char> dict;
+    dict += "{'descr': '";
+    dict += BigEndianTest();
+    dict += map_type(typeid(T));
+    dict += std::to_string(sizeof(T));
+    dict += "', 'fortran_order': False, 'shape': (";
+    dict += std::to_string(shape[0]);
+    for (size_t i = 1; i < shape.size(); i++) {
+      dict += ", ";
+      dict += std::to_string(shape[i]);
+    }
+    if (shape.size() == 1) dict += ",";
+    dict += "), }";
+    // pad with spaces so that preamble+dict is modulo 16 bytes. preamble is 10 bytes.
+    // dict needs to end with \n
+    int remainder = 16 - (10 + dict.size()) % 16;
+    dict.insert(dict.end(), remainder, ' ');
+    dict.back() = '\n';
+
+    std::vector<char> header;
+    header += (char)0x93;
+    header += "NUMPY";
+    header += (char)0x01; // major version of numpy format
+    header += (char)0x00; // minor version of numpy format
+    header += (uint16_t)dict.size();
+    header.insert(header.end(), dict.begin(), dict.end());
+
+    return header;
+  }
+
+} // namespace cnpy
diff --git a/externals/lcov/.version b/externals/lcov/.version
new file mode 100644
index 0000000000000000000000000000000000000000..ad1509c1e5fe761b2edd59aa9b46c4b9320e104f
--- /dev/null
+++ b/externals/lcov/.version
@@ -0,0 +1,3 @@
+VERSION=1.14
+RELEASE=1
+FULL=1.14
diff --git a/externals/lcov/CHANGES b/externals/lcov/CHANGES
new file mode 100644
index 0000000000000000000000000000000000000000..2e7086b994138249ee8f24b93a297015fc4fb245
--- /dev/null
+++ b/externals/lcov/CHANGES
@@ -0,0 +1,3454 @@
+commit 6c7ad581ab9ed66f80050970c0d559c6684613b7 (HEAD, tag: v1.14, origin/master, origin/HEAD, master)
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Feb 28 18:01:39 2019 +0100
+
+    lcov: Finalize release 1.14
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+
+commit 29814f18ec207ebaefa7b41f6e5acc4eca6d7a7a
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Feb 28 17:31:17 2019 +0100
+
+    geninfo: Fix missing FN: entries in result files
+    
+    geninfo sometimes fails to correctly collect function starting lines for
+    some source files, resulting in output files with missing FN: lines.
+    Also such functions are missing from the function list in HTML output.
+    
+    The problem occurs when
+      a) multiple source files contribute to a function implementation (e.g.
+         via including code), and
+      b) the source file that contains the initial function definition
+         is not the source file that contains the most function
+         definitions
+    
+    The problem occurs due to a heuristic in function graph_find_base() that
+    incorrectly determines the source file for a function in this situation.
+    
+    Fix this by using the first file that contributes to a function as the
+    base source file for that function. Only apply this change to data
+    collected using GCC versions 4 and above since earlier versions did not
+    produce stable file orders in graph files.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Reported-by: Joshua Cranmer
+
+commit 74bae96e8ef724eb9dbdf126adad17505375e149
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Feb 28 16:15:22 2019 +0100
+
+    Makefile: Make Perl path install-time configurable
+    
+    Add support for specifying the Perl interpreter path used in installed
+    Perl scripts. If no path is specified, the default '/usr/bin/perl' is
+    used.
+    
+    Set variable LCOV_PERL_PATH to specify a different path, for example:
+    
+      make install LCOV_PERL_PATH=/usr/local/bin/perl
+    
+    Unset this variable to keep the current path:
+    
+      make install LCOV_PERL_PATH=
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+
+commit 0b378cba2c0f93d728627aa8750849d3c33de0e1
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Feb 28 14:21:18 2019 +0100
+
+    bin,test: Use /usr/bin/env to locate script interpreters
+    
+    Make use of the /usr/bin/env tool to locate script interpreters. This is
+    needed to locate the correct interpreter in non-standard environments.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Suggested-by: Bjørn Forsman <bjorn.forsman@gmail.com>
+    Suggested-by: Mario Costa
+
+commit 2ff99aefbd0c80fe0cfddf1e09a596d7344533e1
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Feb 28 14:09:42 2019 +0100
+
+    bin/*: Remove '-w' from interpreter specifications
+    
+    Replace '-w' flag from Perl interpreter specifications with 'use strict'
+    directive. This is done in preparation of using a more flexible
+    interpreter specification.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+
+commit 3b378b0e76be95971680056d864d0e13f4a08557
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Wed Feb 27 16:33:42 2019 +0100
+
+    geninfo: Fix errors while resolving /././ path components
+    
+    Trying to collect code coverage data for source code that contains
+    repeat ./ references in a path components fails with the following
+    error message:
+    
+      geninfo: WARNING: cannot find an entry for <name>.gcov in .gcno file,
+               skipping file!
+    
+    This is caused by a bug in path normalization function
+    solve_relative_path() that does not correctly process adjacent ./
+    references.
+    
+    Fix this by repeating the resolution of ./ references in path
+    components.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Reported-by: Joshua Cranmer
+
+commit 42b55f5a497d2286566d0dd411e3e52fd4d50469
+Author: iignatyev <igor.v.ignatiev@gmail.com>
+Date:   Wed Feb 6 11:35:02 2019 -0800
+
+    geninfo: preserve-paths makes gcov to fail for long pathnames
+    
+    geninfo uses '--preserve-paths' gcov option whenever gcov supports it, this
+    forces gcov to use a whole pathname as a filename for .gcov files. So in cases
+    of quite large pathnames, gcov isn't able to create .gcov files and hence
+    geninfo can't get any data. The fix replaces usage '--preserve-paths' with
+    '--hash-filenames' when it is available.
+    
+    Signed-off-by: Igor Ignatev <igor.v.ignatiev@gmail.com>
+
+commit 04335632c371b5066e722298c9f8c6f11b210201
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Fri Jan 11 13:53:33 2019 +0100
+
+    geninfo: Fix "Can't use an undefined value" error
+    
+    When run on data for source code that causes gcc 8 to generate
+    artificial functions, geninfo emits warnings and eventually aborts
+    processing:
+    
+      geninfo: Use of uninitialized value in hash element at
+               /usr/local/bin/geninfo line 3001.
+      geninfo: Can't use an undefined value as an ARRAY reference at
+               /usr/local/bin/geninfo line 2889.
+    
+    This problem was introduced by commit 9aa0d14a ("geninfo: Ignore
+    artificial functions during --initial"). It is the result of an
+    incomplete removal of artificial functions from internal data.
+    
+    Fix this by explicitcly removing known artificial functions after
+    parsing of graph files completes.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Reported-by: Steven Peters <scpeters@osrfoundation.org>
+
+commit 9aa0d14af4446ef46d80356849a97bc961a91f97
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Jan 10 13:20:15 2019 +0100
+
+    geninfo: Ignore artificial functions during --initial
+    
+    Graph files generated by gcc 8 may contain "artifical" functions that do
+    not exist in a source file. geninfo incorrectly generates coverage data
+    for these functions when run with option --initial.
+    
+    Fix this by filtering out artifical functions when generating initial
+    coverage data.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Reported-by: Marcin Konarski <marcin.konarski@codestation.org>
+
+commit 1e0df571198229b4701100ce5f596cf1658ede4b
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Thu Jan 10 11:39:07 2019 +0100
+
+    geninfo: Fix data collection for files containing templates
+    
+    When using gcc 8, lcov/geninfo produces corrupt coverage output for
+    source code that contains templates or other constructs that cause gcov
+    to produce multiple versions of output for some lines and branches.
+    
+    This is caused by an incorrect check for duplicate output in function
+    read_gcov_file() that is triggered when a template consists of multiple
+    lines, or contains branches.
+    
+    Fix this by ensuring that duplicate lines in per-instance gcov output are
+    correctly ignored. Only the initial occurrence of each line containing
+    the combined coverage of all instances will be processed by geninfo.
+    
+    Note that for branch coverage, gcov doesn't provide a combined view and
+    geninfo processes all branches provided. This should not be a problem
+    though as genhtml will combine the branch data when generating HTML
+    output.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+
+commit abd8bed2b013334d4ef978abadbfff6cc6f3d55d
+Author: MarcoFalke <falke.marco@gmail.com>
+Date:   Tue Jan 8 12:49:00 2019 +0100
+
+    genhtml: Unconditionally include anchor for each named line
+    
+    This helps with referencing the line in the html when sharing links.
+    
+    Signed-off-by: MarcoFalke <falke.marco@gmail.com>
+
+commit 28675dc7564aaa1ad231a7ac23106512a3956d68
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Tue Dec 18 13:07:58 2018 +0100
+
+    genhtml: Use gmtime for SOURCE_DATE_EPOCH conversion
+    
+    By changing that localtime to gmtime the "Known bug" section of the
+    commit message can be removed.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Suggested-by: Bjørn Forsman <bjorn.forsman@gmail.com>
+
+commit 180286bec651928c41de4d6ce3a8760678b38f60
+Author: Bjørn Forsman <bjorn.forsman@gmail.com>
+Date:   Tue Dec 4 14:30:28 2018 +0100
+
+    genhtml: honor the SOURCE_DATE_EPOCH variable
+    
+    Implement the SOURCE_DATE_EPOCH specification[1] for reproducible
+    builds. If SOURCE_DATE_EPOCH is set, use it as timestamp instead of the
+    current time.
+    
+    In this context, reproducible builds means reproducible HTML coverage
+    reports.
+    
+    Known bug: the specification[1] says to defer converting the timestamp
+    to local timezone at presentation time. This is currently not happening;
+    it's converted at build time.
+    
+    [1] https://reproducible-builds.org/specs/source-date-epoch/
+    
+    Signed-off-by: Bjørn Forsman <bjorn.forsman@gmail.com>
+
+commit 41e07cadeeae3054ac22202d5b0b0f0ef6e26467
+Author: Bjørn Forsman <bjorn.forsman@gmail.com>
+Date:   Tue Dec 4 14:30:27 2018 +0100
+
+    Tolerate CDPATH being set
+    
+    If CDPATH is set, cd will print the path it enters, resulting in TOOLDIR
+    containing the path twice, separated by a newline.
+    
+    Signed-off-by: Bjørn Forsman <bjorn.forsman@gmail.com>
+
+commit a3bbe8f0398a3c36b4228cc173e4739d27a863e1
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Mon Dec 10 13:58:10 2018 +0100
+
+    CONTRIBUTING: Clarify patch format requirements
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+
+commit e6750800fe4cb89eda1ff80b7a5fe70fe87ede36
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Tue Nov 13 17:28:17 2018 +0100
+
+    geninfo: Fix accounting of basic blocks in exceptional paths
+    
+    Basic blocks that are not executed and are only reachable via
+    exceptional paths are marked with a '%%%%%' marker in the GCOV output of
+    current GCC versions. Fix geninfo to also recognize this marker.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+    Reported-by: trotux (github user)
+
+commit 94eac0ee870e58630d8052dca1181b0cf802525f
+Author: Peter Oberparleiter <oberpar@linux.ibm.com>
+Date:   Mon Jul 16 13:24:58 2018 +0200
+
+    lcov: Fix branch coverage summary
+    
+    When combining two data files A (without branch coverage data) and B
+    (with branch coverage data), lcov will incorrectly report no branch
+    coverage data for the resulting file in program output, even though the
+    resulting file contains branch coverage data. This only happens when A
+    is specified first during the add operation.
+    
+    This is due to a bug in lcov that loses the correctly combined branch
+    coverage data internally in function brcount_db_combine() when its first
+    parameter is undefined. Fix this by ensuring that the first parameter is
+    an empty hash reference instead.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
+
+commit a5dd9529f9232b8d901a4d6eb9ae54cae179e5b3
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Mar 7 14:18:55 2018 +0100
+
+    geninfo: Add gcc 8 support
+    
+    Fix errors and incorrect data when trying to collect coverage data
+    for programs compiled with gcc 8.
+    
+    Covers the following gcov-related changes in gcc:
+    
+    .gcov-file format:
+      - Line coverage data can appear multiple times for the same line
+      - Line coverage count can be suffixed by '*' to indicated unexecuted
+        basic blocks in that line
+    
+    .gcno-file format:
+      - new header field 'support unexecuted blocks flag'
+      - new function record fields 'column number', 'ending line number',
+        and 'compiler-generated entity flag'
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit c30d88a3a8096dbb3f968de999480c3dc2dedb5f
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue Jan 30 15:12:09 2018 +0100
+
+    genhtml: Implement option to show miss counts
+    
+    Add new command line option --missed that can be used to show the
+    number of missed lines, functions, or branches.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 999abf2447b4df373b135dc3f8ee317350bd95f8
+Author: Benoit Belley <Benoit.Belley@autodesk.com>
+Date:   Fri Oct 6 10:01:28 2017 -0400
+
+    Adding the --include and --exclude options to lcov and geninfo
+    
+    * The --include command-line option allows the user to specify a regular
+      expression for the source files to be included. The command-line
+      option can be repeated to specify multiple patterns. The coverage
+      information is only included for the source files matching at least
+      one of the patterns.
+    
+      The "lcov --capture --include" (or "geninfo --include") option is
+      similar in functionality to the "lcov --extract" command-line
+      option. But, by directly using applying the pattern while capturing
+      coverage data one can often avoid having to run "lcov --extract" as a
+      second pass.
+    
+    * The --exclude command-line option allows the user to specify a regular
+      expression for the source files to be excluded. The command-line
+      option can be repeated to specify multiple patterns. The coverage
+      information is excluded for source files matching at least one of the
+      patterns.
+    
+      The "lcov --capture --exclude" (or "geninfo --exclude") option is
+      similar in functionality to the "lcov --extract" command-line
+      option. But, by directly using applying the pattern while capturing
+      coverage data one can often avoid having to run "lcov --remove" as a
+      second pass.
+    
+    * On one of our code base at Autodesk, this speeds-up the generation of
+      HTML code coverage reports by a factor of 3X.
+    
+    Signed-off-by: Benoit Belley <benoit.belley@autodesk.com>
+
+commit b6a11368c3cdc86c4e147ccd8e539918dfe37900
+Author: Ziqian SUN (Zamir) <zsun@redhat.com>
+Date:   Wed Jul 19 10:58:24 2017 +0800
+
+    Resolve some rpmlint issue in SPEC.
+    
+    Following messages reported by rpmlint on RHEL is fixed by this patch:
+    lcov.src: W: invalid-license GPL
+    lcov.src:9: W: hardcoded-path-in-buildroot-tag
+    /var/tmp/%{name}-%{version}-root
+    lcov.src: E: specfile-error warning: bogus date in %changelog: Fri Oct 8
+    2002 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+    lcov.noarch: W: non-conffile-in-etc /etc/lcovrc
+    
+    Signed-off-by: Ziqian SUN (Zamir) <zsun@redhat.com>
+    [oberpar@linux.vnet.ibm.com: Corrected license to GPLv2+]
+
+commit a77a7628ef5377c525a0d4904cc0b73eeede4d7c
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Fri Apr 7 15:43:28 2017 +0200
+
+    genhtml: Reduce path resolution overhead
+    
+    Reduce overhead when reading coverage data files by consolidating
+    calls to Cwd:cwd().
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 526c5148ac0add40ef1224d2cdabdec73ce3f899
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Fri Apr 7 15:37:52 2017 +0200
+
+    genhtml: Reduce load times for complex coverage data files
+    
+    genhtml uses a significant amount of time loading coverage data files
+    containing complex branch coverage data (i.e. data with a large number
+    of branches per basic block). Most of this time is spent storing
+    branch coverage data in a vector-based data representation, with an
+    unnecessary amount of cross-checking being done for existing branch
+    data.
+    
+    Fix this by replacing the vector based data representation by two
+    separate representations, scalar for storage and hash for processing,
+    and by moving cross-checking out of the hot path. This results in a
+    significant speedup at the cost of a minor increase in memory usage.
+    
+    Test results for "make -C genhtml_output/ SIZE=large":
+    
+    Original:
+      6 tests executed, 6 passed, 0 failed, 0 skipped (time 768.4s, mem
+      893.8MB)
+    
+    Patched:
+      6 tests executed, 6 passed, 0 failed, 0 skipped (time 202.3s, mem
+      908.10MB)
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 0f07133f184af6670bdf1edf39fca9d2e90e9ad2
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Fri Apr 7 14:38:22 2017 +0200
+
+    test: Add self-tests for genhtml
+    
+    Add some tests for checking basic functionality of genhtml.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 544a6951db25679792bb0648006a897ea564d883
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Fri Apr 7 14:32:47 2017 +0200
+
+    genhtml: Ensure stable block order in branch output
+    
+    Sort order of basic blocks in output of branch coverage data. This
+    allows for a better comparison of output between test cases.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 477957fa4c6c104d5842911682ec17d6ad2d2980
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Thu Apr 6 12:28:11 2017 +0200
+
+    lcov: Reduce load times for complex coverage data files
+    
+    lcov uses a significant amount of time loading coverage data files
+    containing complex branch coverage data (i.e. data with a large number
+    of branches per basic block). Most of this time is spent storing
+    branch coverage data in a vector-based data representation, with an
+    unnecessary amount of cross-checking being done for existing branch
+    data.
+    
+    Fix this by replacing the vector based data representation by two
+    separate representations, scalar for storage and hash for processing,
+    and by moving cross-checking out of the hot path. This results in a
+    significant speedup at the cost of a minor increase in memory usage.
+    
+    Test results for "make test SIZE=large":
+    
+    Original:
+      17 tests executed, 17 passed, 0 failed, 0 skipped (time 1883.9s, mem
+      2459.0MB)
+    
+    Patched:
+      17 tests executed, 17 passed, 0 failed, 0 skipped (time 283.6s, mem
+      2544.2MB)
+    
+    Note that this fix only applies to the lcov tool. The same work is
+    necessary for genhtml.
+    
+    This approach was inspired by a patch by creich.3141592@gmail.com.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 3b397a3f3acdb62080e8366130758cb34703cfbf
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Thu Apr 6 09:01:36 2017 +0200
+
+    test: Improve test framework
+    
+    Various improvements to lcov's self-test framework:
+     - Add test case for lcov --diff
+     - Add new verbosity level
+     - Enable normalization of coverage data files from stdin
+     - Fix lcov_add_concatenated4 test name
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 53a6ce8ef604173b6de874a534a30121392d7cd0
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Thu Mar 30 15:42:56 2017 +0200
+
+    lcov: Add self-tests
+    
+    Add some tests for checking basic functionality of lcov. To run these
+    tests, type:
+    
+    	make test
+    
+    in either the top-level directory, or the test/ sub-directory.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 9753d5c0da107919537e91e504551e4ab3bccc2f
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Thu Mar 30 15:31:34 2017 +0200
+
+    lcov: Fix output on stderr for --summary
+    
+    Some functions of lcov erroneously print informational output to stderr
+    instead of stdout as expected. Fix this by inverting the "to_file" logic
+    in lcov to a "data_stdout" logic. Affected functions are --summary,
+    --reset and --list.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 25f5d38abad20eeaa407f62f53c3c00dfbbd0bf3
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Mar 6 09:51:00 2017 +0100
+
+    lcovrc.5: Add genhtml_demangle_cpp default and CLI reference
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 66db744a1d63c5d3b1dee2d8a2ce76e6e06c7255
+Author: Katsuhiko Nishimra <ktns.87@gmail.com>
+Date:   Fri Mar 3 17:47:48 2017 +0900
+
+    Support passing demangle-cpp option via lcovrc
+    
+    This patch allows users to passing the demangle-cpp option to genhtml
+    via lcovrc, alongside with CUI.
+    
+    Signed-off-by: Katsuhiko Nishimra <ktns.87@gmail.com>
+
+commit b6fb452addaa6a33dcb37c101879b8b5e1e0c34c (tag: v1.13)
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Dec 19 15:20:40 2016 +0100
+
+    lcov: Finalize release 1.13
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit daca8d9febe52ccf1976240a3b48ffc350dec902
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Dec 19 14:36:00 2016 +0100
+
+    geninfo: Fix 'unexpected end of file' error
+    
+    Use the compiler version as stored in the .gcno file to determine if
+    the file contains function records with split checksums. This fixes
+    the following problem that can occur when lcov is run using a gcov
+    tool of GCC version 4.7 and above on .gcno files compiled with a
+    version below 4.7:
+    
+      # lcov -c -d . -o test.info --initial
+      [...]
+      geninfo: ERROR: test.gcno: reached unexpected end of file
+    
+    Also add missing lcov version to --debug output.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit a90d50e97cb49ea712c94d91cdef1cc21a3c7986
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Dec 14 11:00:08 2016 +0100
+
+    lcov: Remove use of install -D option
+    
+    Some versions of the install tool don't support the -D option, causing
+    a 'make install' call to fail. Fix this by replacing the -D option with
+    two calls to install, first to create all target directory components,
+    then to install the actual files.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+    Reported-by: <deanyang@tencent.com>
+
+commit 6ec3f2398d22e605c1a8019541fb32d26d18044b
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Fri Oct 7 09:47:35 2016 +0200
+
+    genhtml: Fix warning with small genhtml_line_field_width
+    
+    On systems with Perl versions 5.21 and above, genhtml prints a warning
+    similar to the following during processing:
+    
+      genhtml: Negative repeat count does nothing at bin/genhtml line 3854,
+               <SOURCE_HANDLE> line 4.
+    
+    This is due to size calculations resulting in a negative number of
+    padding characters when genhtml_line_field_width is lower than the size
+    of the strings to pad (9). Fix this by disabling padding in these cases.
+    
+    Reported-by: xaizek@openmailbox.org
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit d7cc7591b3a7cc1ec95371d04e4fc46f10b3fd54
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue Oct 4 09:50:52 2016 +0200
+
+    geninfo: Fix gcov version detection for XCode 8.0
+    
+    The LLVM gcov version included in XCode 8.0 reports its version in a
+    format that is not understood by geninfo, resulting in the wrong format
+    of coverage data files being expected. Fix this by reworking gcov
+    version detection in geninfo to be more robust.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 68320d932c5ee5537ae1c287fe52603ae2fecf8c
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Aug 22 15:54:56 2016 +0200
+
+    lcov: Update installation mechanism
+    
+    Change default installation location to /usr/local to prevent
+    conflicts with files installed by package managers (reported by
+    Gregory Fong). To achieve this, rename PREFIX to DESTDIR and
+    introduce actual PREFIX Makefile variable and update spec file
+    to install packaged files to previous locations.
+    
+    Also fix spec file to not announce ownership of system directories
+    (reported by and based on patch by Jiri Kastner <jkastner@redhat.com>).
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 04a3c0ed1b4b9750b2ac5060aac0e6d5a3b9da7f
+Author: Benoit Belley <benoit.belley@autodesk.com>
+Date:   Mon Apr 4 18:16:54 2016 -0400
+
+    Pass --no-strip-underscore to c++filt on OS X
+    
+    * The --no-strip-underscope flag is necessary on OS X so that symbols
+      listed by gcov get demangled properly.
+    
+       From the c++filt man page: "On some systems, both the C and C++
+       compilers put an underscore in front of every name.  For example, the
+       C name "foo" gets the low-level name "_foo". This option tells c++filt
+       not to remove the initial underscore.  Whether c++filt removes the
+       underscore by default is target dependent."
+    
+    Signed-off-by: Benoit Belley <benoit.belley@autodesk.com>
+
+commit 632c25a0d1f5e4d2f4fd5b28ce7c8b86d388c91f
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue Mar 8 10:51:51 2016 +0100
+
+    lcov: Fix output files being created in / directory
+    
+    When a warning is emitted by lcov before creating an output file,
+    e.g. when a negative coverage count was found while combining
+    tracefiles, lcov tries to create the output file in the root
+    directory (/) instead of the current working directory.
+    
+    This is a result of lcov's warn handler calling a temp file cleanup
+    routine that changes directories to / before trying to remove its
+    temporary directory.
+    
+    Fix this by removing the temp cleanup call from the warn handler.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit e32aab1b4c85503a6592a91326c4b362613e1d66
+Author: Gabriel Laskar <gabriel@lse.epita.fr>
+Date:   Wed Feb 10 09:56:18 2016 +0100
+
+    lcov: Fix --remove pattern matching
+    
+    The --remove option of lcov now consider the pattern passed as parameter
+    as a full path, and not only a part of the filename.
+    
+    This behavior was discovered by using AX_CODE_COVERAGE[1] m4 macro from
+    a directory in $HOME/tmp. The macro itself calls lcov with
+    `--remove "/tmp/*"`.
+    
+    [1]: https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
+    
+    Signed-off-by: Gabriel Laskar <gabriel@lse.epita.fr>
+
+commit 79e9f281ea893b2f6498b4bad79173b1414aa055
+Author: Reiner Herrmann <reiner@reiner-h.de>
+Date:   Fri Oct 30 20:26:59 2015 +0100
+
+    lcov: use UTC to get timezone-independent date
+    
+    The date is used for updating the time inside manpages.
+    If localtime is used, the date could vary depending on the user's
+    timezone. To enable reproducible builds, UTC is used instead.
+    
+    Signed-off-by: Reiner Herrmann <reiner@reiner-h.de>
+
+commit de33f51b49dc6d01a285aa73990f03e7d982beb2 (tag: v1.12)
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Oct 5 17:37:40 2015 +0200
+
+    lcov: Finalize release 1.12
+    
+     - Use full git describe output as tool version
+     - Update version numbers and last-changed-dates in man pages,
+       spec and README file
+     - Replace static CHANGES file with git log
+     - Switch Makefile logic to use mktemp for generating a temporary
+       directory
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 1ad4f7779b7721e311e552209e110e08bbf18fa1
+Author: Denis Abramov <abramov.denis@gmail.com>
+Date:   Mon Sep 21 09:29:20 2015 +0200
+
+    geninfo: Added support for Xcode 7.0 gcov version handling
+    
+    With Xcode 7.0 LLVM gcov keeps version information on the first line.
+    E.g. gcov --version yields: Apple LLVM 7.0.0 (clang-700.0.65)
+    
+    Signed-off-by: Denis Abramov <abramov.denis@gmail.com>
+
+commit c3602ea8e598deda4afff603bb123caa98eef159
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Aug 3 11:05:51 2015 +0200
+
+    genhtml: Allow prefix paths with spaces
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit a3572971367198ef0febe476052640bd09bec931
+Author: Gilles Gouaillardet <gilles@rist.or.jp>
+Date:   Thu Jul 30 14:11:57 2015 +0900
+
+    genhtml: support a comma separated list of prefixes
+    
+    the --prefix option of genhtml now takes a comma separated list of prefixes
+    instead of a single prefix.
+    this can be required when running lcov vs projects configure'd with VPATH
+    and in which source files are both in the source and build directories.
+    
+    Signed-off-by: Gilles Gouaillardet <gilles@rist.or.jp>
+
+commit 997f32ae85717cd47d2305d7cd7ccce3ffa1abe6
+Author: Gilles Gouaillardet <gilles@rist.or.jp>
+Date:   Tue Jun 23 14:28:22 2015 +0900
+
+    Fix find command line
+    
+    find xxx -name \*.gcda -type f -o type l
+    does return :
+    - all files with the .gcda suffix
+    - all symbolic links
+    
+    the updated command line now returns
+    - all files with the .gcda suffix
+    - all symbolic links with the .gcda suffix
+    
+    Signed-off-by: Gilles Gouaillardet <gilles@rist.or.jp>
+
+commit 533db4e78b54ae01e023d00c1fec5dddaaaf37e6
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 17 17:54:20 2015 +0200
+
+    lcov: Fix capture for package files containing graph files
+    
+    Depending on whether package files contain graph files, data should be
+    collected from the unpacked package file directly, or from the build
+    directory after linking data files. This approach fixes problems when
+    capturing coverage data via a package from a directory containing graph
+    files.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit a2a8b376ec5e9e5082a0cbb935137d6a8f526870
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 17 17:34:33 2015 +0200
+
+    lcov: Fix .build_directory file not being deleted
+    
+    Using option --to-package while capturing coverage data creates a
+    temporary file named ".build_directory". Currently this file is not
+    properly removed at the end of processing due to a changed CWD. This
+    patch fixes this problem by reverting to the original CWD before trying
+    to remove the temporary file.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit b9de825f1fe018f381c8859ee0f3f4af15122c7a
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue Jun 16 13:53:00 2015 +0200
+
+    lcov: Enable userspace package capture with only data files
+    
+    Previously lcov's --from-package capture mechanism required
+    that .gcno files and source were present on the test machine.
+    
+    This patch modifies --from-package capturing to work when
+    only .gcda files are present in the package captured on the
+    test machine. It works by linking the .gcda files collected
+    on the test machine into their natural location on the build
+    machine. This requires existing .gcda files to be removed.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 0e4f0908aed3e1a071d5435c36c18cd493f0c309
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue Jun 16 13:33:54 2015 +0200
+
+    lcov: Make package handling more robust
+    
+    Apply some changes to --from-package and --to-package handling
+    to better handle failures:
+    
+     - Abort if tar tool is not available
+     - Abort if no data file is found in package file
+     - Ensure that temporary directories can be deleted
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit f87d980929a5a06d49d0a6856f6c3314418c27ef
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue May 12 17:28:44 2015 +0200
+
+    genhtml: Rework c++filt name demangling
+    
+    When running genhtml with command line option --demangle-cpp, do not
+    merge function call data based on demangled function names. Instead mark
+    duplicate function entries in the function view with a version suffix
+    (.<number>). This resolves problems with entries for functions that
+    demangle to the same name, but begin on different lines according to GCC
+    (e.g. virtual destructors).
+    
+    Reported-by: Lukasz Czajczyk <lukasz.czajczyk@gmail.com>
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 2e872175cbba2c09c9025da2660edf0b4abb55cb
+Author: Daniel Fahlgren <daniel@fahlgren.se>
+Date:   Wed Apr 22 15:17:10 2015 +0200
+
+    geninfo: make line exclusion markers configurable
+    
+    This patch exposes the variable $excl_line and $excl_br_line so they can
+    be set in the configuration file. It is not always possible to add the
+    exclusion markers to the code with reasons like third party code,
+    company policy, legacy code, no commit access etc.
+    
+    One obvious use case is to exclude assert() from the branch coverage and
+    abort() from line coverage. They are never meant to be triggered unless
+    something is wrong. Other use cases can be custom error handling macros
+    or macros that depend on endianness, like htons().
+    
+    Signed-off-by: Daniel Fahlgren <daniel@fahlgren.se>
+
+commit 10b11eaa178976d1433007adb2188d05b8605be6
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Nov 10 17:17:23 2014 +0100
+
+    geninfo: Ignore empty .gcno files with --initial
+    
+    Some versions of GCC create empty .gcno files which cause geninfo
+    to abort processing with an error message:
+    
+      geninfo: ERROR: dummy.gcno: reached unexpected end of file
+    
+    Fix this problem by skipping empty .gcno files.
+    
+    Reported-by: Maarten Hoes <hoes.maarten@gmail.com>
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit f9d8079646aa906518c4ab7d326504e6837532a7
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Mon Nov 10 16:54:08 2014 +0100
+
+    lcov: Fix warning when specifying --rc
+    
+    Current Perl versions report the following warning when using the --rc
+    option of lcov:
+    
+      lcov: Use of each() on hash after insertion without resetting hash
+      iterator results in undefined behavior
+    
+    Fix this warning by not modifying the hash variable that is being
+    iterated on. Also add the missing whitespace fix-up of --rc parameters
+    to genhtml.
+    
+    Reported-by: Maarten Hoes <hoes.maarten@gmail.com>
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 2a634f6caa98f979606189ec3ee98f4cac270b97
+Author: Philip Withnall <philip.withnall@collabora.com>
+Date:   Mon Nov 10 14:58:34 2014 +0000
+
+    genhtml: Support relative source filenames in SF keys
+    
+    Some tools which generate .info files generate relative filenames for
+    the ‘SF’ keys. For example, nodeunit’s lcov output does. When genhtml is
+    run with --output-directory, it calls chdir() which breaks relative
+    lookup of the source files. Fix that by resolving all source filenames
+    to absolute paths when loading an info file, resolving any relative ones
+    using the info file’s path as a base.
+    
+    Signed-off-by: Philip Withnall <philip.withnall@collabora.co.uk>
+
+commit b4344c6a5d3c434ca0d801c197a09cfdeecb3f32
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Fri Sep 26 13:11:18 2014 +0200
+
+    man: Add description for --precision and genhtml_precision
+    
+    Add man page sections for genhtml's command-line option --precision
+    and lcovrc configuration setting genhtml_precision. Also add an
+    example configuration setting in lcovrc.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit aa1217412f1e8b540010fea5ca9844b9e4699e54
+Author: Euccas Chen <euchen@qti.qualcomm.com>
+Date:   Fri Sep 26 12:53:29 2014 +0200
+
+    genhtml: Implement option to specify coverage rate precision
+    
+    Add command line support and config file support for specifying the
+    coverage rate precision, valid precision range: [1,4].
+    
+    Signed-off-by: Euccas Chen <euchen@qti.qualcomm.com>
+
+commit 4d4eba1a8b5e7d2a6c5e93c0a50264da1a5c5540
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 25 09:41:59 2014 +0200
+
+    get_version.sh: Remove - characters from release string
+    
+    Replace - with . in release strings to fix the following build
+    error in the dist Makefile target:
+    
+      error: line 4: Illegal char '-' in: Release: 4-g1d44b2a
+      make: *** [rpms] Error 1
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit ffbd3e08cc0871842b2205b0b73c2ae8f3ad02e8
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 25 09:25:50 2014 +0200
+
+    genhtml: Improve demangle error message
+    
+    Improve error message that is shown when there are mangled function name
+    entries on different lines that demangle to the same clear text function
+    name.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 1d44b2a090aa933b15e4cafc1a440ccb390df92e
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Tue Jun 24 17:45:34 2014 +0200
+
+    geninfo: Fix error when using --demangle-cpp
+    
+    Using genhtml's --demangle-cpp option on data produced with recent GCC
+    versions (at least 4.8 and 4.9) can result in an error message similar
+    to the following:
+    
+      genhtml: ERROR: Demangled function name _ZN3subD2Ev  maps to different
+               lines (5 vs 4)
+    
+    The reason for this error is an unexpected sequence of lines records
+    in a .gcno file. These records mention line numbers as belonging to a
+    function which occur before the initial line number of that function
+    as reported by the corresponding function record.
+    
+    Fix this problem by retaining the order of lines belonging to a function
+    as found in the .gcno file. This way geninfo will consistently use the
+    initial line number as reported by the function record when merging
+    function data during the demangling process.
+    
+    Reported-by: Alexandre Duret-Lutz <adl@lrde.epita.fr>
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 566e5ec7e69a03612e1ed4961779d939af180d66
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 18 16:05:29 2014 +0200
+
+    lcov: Remove unused files
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit c76172bfe630520e217ecc0bca8f18481c4c33b0
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 18 16:01:05 2014 +0200
+
+    README: Fix typo
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit a6b10a41056cd10c7b735e259fee81f1865c2109
+Author: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+Date:   Wed Jun 18 15:50:04 2014 +0200
+
+    lcov: Remove CVS artifacts
+    
+    Replace CVS specifics in the build environment and tools source with
+    Git mechanisms:
+     * CONTRIBUTING and README file now refer to github for the primary
+       source location
+     * When run from a Git repository, the tools dynamically determine the
+       Git version using 'git describe'
+     * When installed into the file system, the version information is
+       fixed with the current Git version
+     * When preparing distribution files, the version at the time of
+       preparing the files is written to file ".version"
+    
+    Also add a .gitignore file to filter out the most frequent temporary
+    file types.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit fa2a991cf6fad37fec7650b95be705df143e058a (tag: v1.11)
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri May 23 08:56:17 2014 +0000
+
+    lcov: finalizing release 1.11
+
+commit e2729beea0d7769ef0e992c27a294b0742a6ac77
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri May 23 08:47:10 2014 +0000
+
+    CHANGES: update
+
+commit 866d187602bfc2e3a8199f4e9e9430ef38f106a8
+Author: Jeffrey Hutzelman <jhutz@cmu.edu>
+Date:   Tue May 20 14:12:55 2014 +0000
+
+    lcov: Sort branches in unnamed blocks first
+    
+    When processing branch coverage data, consider branches in "unnamed"
+    blocks to come before other blocks on the same line, so that they
+    appear in the correct order in HTML output.
+    
+    This is accomplished by using block number -1 for unnamed blocks,
+    instead of 9999 as was previously done.  In branch data vectors, this
+    is reprsented by the value $BR_VEC_MAX, which is defined to be the
+    largest value representable in the field width used.  This same value
+    is also used in .info files, for backward-compatibility with regular
+    expressions used to parse these files.  As a result, .info files
+    generated by versions of lcov with this change can be read by older
+    versions, though branch results will still appear out of order.
+    
+    Signed-off-by: Jeffrey Hutzelman <jhutz@cmu.edu>
+
+commit 17c0edec32193b9e8058908447d3eb403d76c8de
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu May 15 10:23:45 2014 +0000
+
+    lcov: Update man page
+    
+    Add missing description for command line parameter value.
+    
+    Reported-by: sylvestre@mozilla.com
+
+commit c0958139e015805cce15b60b740c735690ad4002
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Apr 14 12:14:55 2014 +0000
+
+    genhtml: Implement option to allow HTML in test description
+    
+    Add lcovrc directive genhtml_desc_html to allow using HTML markup in
+    test case description text.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 4f2c3aefcfcf816806da83a8609bd743eb227d37
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Apr 14 11:24:05 2014 +0000
+
+    genhtml: Check for proper description file format
+    
+    Ensure that description files contain test name lines before test
+    description lines. This fixes a "use of uninitialized value" warning
+    in genhtml.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 3a68239905c28a7c3bfac52172a254872d6a7aa7
+Author: Jonah Petri <jonah@petri.us>
+Date:   Mon Apr 14 11:06:21 2014 +0000
+
+    lcov: make geninfo compatible with LLVM's gcov
+    
+    These changes are needed to make geninfo compatible with LLVM's gcov:
+    * Use --version rather than -v to probe version info
+    * Convert LLVM gcov version numbers to the GCC gcov version they emulate
+    * Translate short options into their equivalent long option capabilities
+    
+    Signed-off-by: Jonah Petri <jonah@petri.us>
+
+commit a74bdeeae0383b197b1dafa44d01a54129fb3d7c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 8 13:26:04 2014 +0000
+
+    genhtml: Reduce hash copying while adding up files
+    
+    Reduce copying effort and memory usage. Based on similar patch for
+    lcov by olly@survex.com.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit c6b4d91fdf667cfca17213742e2e04f6281ebed4
+Author: Olly Betts <olly@survex.com>
+Date:   Wed Jan 8 13:14:05 2014 +0000
+
+    lcov: Avoiding copying hashes passed to add_counts function
+    
+    This patch reduces memory usage - without it lcov was failing every time
+    for me with out of memory errors in a VM with 1GB of RAM and 1GB of
+    swap, but with it lcov completes every time.
+    
+    It's presumably also faster to avoid these copies.
+    
+    Signed-off-by: Olly Betts <olly@survex.com>
+
+commit cf6f2e685510da62bd2eb1f386f71d57c41f4594
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Dec 13 16:09:05 2013 +0000
+
+    geninfo: Tolerate garbage at end of gcno file
+    
+    Some versions of gcc produce garbage at the end of a gcno file
+    when recompiling a source code file after removing some lines.
+    
+    This patch makes geninfo's gcno file parser more robust by assuming
+    end-of-file when it finds a record that extends beyond the end-of-file.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 14286b29d076208452da6021c792ebf43552ac2c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Dec 13 15:23:27 2013 +0000
+
+    geninfo: make gcov tool version detection more robust
+    
+    Don't consider gcov tool version information in parenthesis when
+    determining the gcov tool version. This fixes problems where the
+    version string contains a different version number in parenthesis
+    before the actual gcov version.
+    
+    Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+
+commit 0bde87338cd155af46804d77701c93ef263c3d53
+Author: Sebastian Stigler <s_stigler@gmx.de>
+Date:   Fri Dec 13 15:09:58 2013 +0000
+
+    geninfo: add exclude marker for branch coverage
+    
+    Sometimes it can be helpful to generally use branch coverage but to
+    disable it for some lines of code without excluding the line or function
+    coverage too.
+    
+    For example if you make heavily use of assertions in your code (which is
+    generally a good idea) you will see that for each 'assert(...)' exist
+    one branch which is taken and one that is not. Similarly you can see the
+    same phenomenon for 'delete' in C++ code.
+    
+    If you use the 'LCOV_EXCL_LINE' marker in such a situation both of these
+    branches will be omitted from the output. But in doing so, you loose the
+    ability to determine if this peace of code is genuine 'dead code' or not
+    because the line coverage is omitted too.
+    
+    The newly introduces 'LCOV_EXCL_BR_LINE', 'LCOV_EXCL_BR_START' and
+    'LCOV_EXCL_BR_STOP' marker address this problem. The usage is similar to
+    the 'LCOV_EXCL_LINE' etc. markers.
+    
+    Signed-off-by: Sebastian Stigler <s_stigler@gmx.de>
+
+commit 119be727596f567e83b03de384b4150b926911a3
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Dec 12 14:58:44 2013 +0000
+
+    geninfo: Fix handling of non-english locales
+    
+    geninfo expects gcov output in the default C locale. This isn't always
+    given, for example when running in an environment where variable
+    LANGUAGE is set to a non-english locale. In such cases gcov output
+    cannot be correctly parsed, resulting for example in the absence of
+    branch coverage data.
+    
+    gcov uses gettext() for writing internationalized messages. The info
+    page for gettext mentions the order in which locale-defining
+    environment variables are evaluated:
+    
+    LANGUAGE
+    LC_ALL
+    LC_MESSAGES
+    LANG
+    
+    In addition, gettext implements special handling where LC_ALL=C takes
+    precedence over LANGUAGE.
+    
+    geninfo currently only specifies LANG=C. Fix the issue by specifying
+    LC_ALL=C instead.
+    
+    Based on fix suggestion by Sebastian Stigler.
+    
+    Reported-by: Sebastian Stigler <s_stigler@gmx.de>
+
+commit 0f7bb3ebc8487b83ce9b7047c81a3655135876ea
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Dec 9 15:49:35 2013 +0000
+
+    lcov: Added contribution guidelines
+
+commit f83688fe27f133ef02e9ab47a435d6a5d2074932
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 2 07:29:20 2013 +0000
+
+    geninfo: fix --no-external not working with --initial
+    
+    When running lcov --capture --initial together with --no-external.
+    the --no-external has no effect. Fix this by applying the external
+    filtering also for graph files.
+    
+    Reported-by: malcolm.parsons@gmail.com
+
+commit 6a8a678046bd75aa81d30484b1817425022d71e5
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 1 11:49:46 2013 +0000
+
+    lcov: fix --config-file not being passed to geninfo
+    
+    Calling lcov to capture coverage data while specifying --config-file
+    will result in the configuration directives of that file not being
+    used during data collection.
+    
+    Fix this by ensuring that --config-file is passed on to geninfo.
+    
+    Reported-by: liuyhlinux@gmail.com
+
+commit c3be5b6859ef280b469b6b75cf4709fc35f91ced
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu May 2 11:02:24 2013 +0000
+
+    lcov: fix whitespace handling in --rc command line option
+    
+    Specifying blanks around --rc options results in the options not
+    being correctly recognized, for example:
+    
+    This doesn't work:
+    geninfo . -o - --rc="geninfo_adjust_src_path = /tmp => /usr"
+    
+    This works:
+    geninfo . -o - --rc="geninfo_adjust_src_path=/tmp => /usr"
+    
+    Fix this by automatically removing whitespaces at the start and end
+    of --rc options and values.
+
+commit 4699f8d391325335777ed234e388be2e2f87478c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Apr 12 07:51:34 2013 +0000
+
+    README: improve usage hint
+
+commit 36e0539737198ad1bee51103f47842f13c575239
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Mar 13 10:28:07 2013 +0000
+
+    genhtml: add time to date string
+    
+    Add the current time to the date information in the HTML output
+    generated by genhtml. This way users can differentiate results when
+    creating HTML output multiple times a day.
+    
+    Based on patch by sylvestre@debian.org.
+
+commit 38fbe93c8cd8402be8e4821825fdeeaa23e8367c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Feb 22 14:09:08 2013 +0000
+
+    geninfo: don't warn about missing .gcov files
+    
+    Newer versions of gcc remove .gcov files for source files that do
+    not contribute instrumented lines. Remove the
+    
+      WARNING: no data found for file.c
+    
+    warning that geninfo issues in this case.
+
+commit 29346542c30af221a2ffdfe097fbd858044b712a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Feb 1 11:44:03 2013 +0000
+
+    genhtml: fix handling of user-specified prefixes with trailing /
+    
+    A trailing / in a user-specified prefix is not correctly recognized.
+    Fix this by removing any number of trailing / in a user-specified
+    prefix. Reported by ahmed_osman@mentor.com.
+
+commit 5241e2afadca5f172bd0b8cafe61e20d2153f0bf
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 30 11:46:42 2013 +0000
+
+    lcov: fix bug when converting function data in --diff operation
+    
+    When a patch is applied to a tracefile using command line option --diff
+    and the patch changes the list of functions, the operation aborts with
+    the following error:
+    
+      lcov: Use of freed value in iteration at lcov line 3718.
+    
+    Fix by applying missing calls to keys() when iterating function data
+    hashes. Reported by Nasir.Amanullah@us.fujitsu.com.
+
+commit 9ce8d8cb4f978eb80fb88ecafd52e869fab75d8f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 25 16:30:25 2013 +0000
+
+    lcov/genhtml: fix outdated comment regarding data structure
+
+commit c85e73a36e3f8c4e7fab888ac1536bee94a6fe56
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 25 16:29:30 2013 +0000
+
+    genhtml: merge function data during demangling
+    
+    Merge function execution counts when multiple function names demangle
+    to the same name.
+
+commit 2dfafc99c1eccbb81066436845e06a868eb3c434
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 25 11:46:28 2013 +0000
+
+    genhtml: improve function table sorting
+    
+    In the function table view, the initial view should show the functions
+    sorted by execution count because - unlike with file names - the function
+    name is not a natural order for functions (the line number would be,
+    but that is not available). Also sort functions with the same execution
+    count alphabetically for a stable order.
+    
+    Base on a suggestion by paul.bignier@hotmail.fr.
+
+commit 331a29011709a27d2ec11c6cbd6ac51dfdaf70c6
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 23 16:52:06 2013 +0000
+
+    genhtml: consolidate calls to c++filt
+    
+    When using --demanglecpp, call c++filt only once instead of per
+    function. This approach can reduce the run-time for source files
+    with a lot of overloaded functions significantly. Based on idea
+    by olly@survex.com.
+
+commit 49b877160b1d28cd6c3d8332d5d47c9c74420070
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Jan 10 09:02:32 2013 +0000
+
+    geninfo: make empty data directories non-fatal
+    
+    Emit a warning when no data file is found in a data directory
+    to allow processing of additional directories.
+    
+    Based on suggestion by rich_drake@yahoo.com.
+
+commit 3836c162c2864ed180df7d80fa03c70d17102edc
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Nov 13 09:58:53 2012 +0000
+
+    geninfo: fix parsing of gcc 4.7 gcov format
+    
+    GCC 4.7 changes the gcov format for lines which can only be reached
+    by exceptions to "=====" instead of "#####". This results in the
+    following warning:
+    
+    geninfo: Argument "=====" isn't numeric in numeric gt (>) at geninfo
+    line 1281.
+    
+    Fix this by handling "=====" correctly.
+
+commit b932f94cc83c3df169c76689533336bba4de4dba
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Oct 10 09:14:17 2012 +0000
+
+    lcov.spec: back to CVS version
+
+commit 6af00fa26e1a91a39c873ff9fa6df7fb8830ec42
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Oct 10 09:12:42 2012 +0000
+
+    lcov.spec: fix Perl dependency
+
+commit 4eac16e93db328e86e44da40e3d5e96a0301d361
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Oct 10 08:36:16 2012 +0000
+
+    lcov: update CVS version to 1.11-pre1
+
+commit b5c1bdddd1380be3ad12952ed2747df3744e227e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Oct 10 08:20:21 2012 +0000
+
+    lcov: finalizing release 1.10
+
+commit 089861768a94d0f6e827539c828f19141092f529
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Oct 10 08:07:54 2012 +0000
+
+    CHANGES: update
+
+commit 9037de17458c5d9767d201bd0599d40347a9bc41
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Oct 10 08:07:01 2012 +0000
+
+    genhtml: handle source files in root directory gracefully
+
+commit 68dd0f19da0d8d6e82375e09b97f7ffc22847db4
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Oct 9 13:58:22 2012 +0000
+
+    geninfo: add automatic detection of base directory
+    
+    Add a heuristic to automatically determine the base directory
+    when collecting coverage data. This heuristic should cover many,
+    if not most cases of build systems moving files around during
+    compilation (e.g. libtool, automake, etc.). The heuristic can be
+    enabled or disabled using the configuration file directory
+    'geninfo_auto_base'.
+
+commit 631d2b11bfde56ffca4568382abf5d90653c4141
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Oct 8 15:03:23 2012 +0000
+
+    geninfo: fix missing line data after last commit
+
+commit b1e14c4a1a0f3ccaad0c665f439624cf4588a68d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Oct 8 13:02:45 2012 +0000
+
+    lcov: add missing help text for option --rc
+
+commit a432efff6ee8485ec0724aca4eae79a4c390a328
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 5 15:53:09 2012 +0000
+
+    lcov: updated CHANGES file and copyright years
+
+commit 897322ecdb858f18e4a12f4716bbb08c067b6c9c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 5 15:20:41 2012 +0000
+
+    geninfo: fix warning about unhandled .gcov files
+    
+    gcov will sometimes create .gcov files that contain no instrumented
+    line. When geninfo reads .gcno files it filters out such files,
+    resulting in the following warning:
+    
+    geninfo: WARNING: cannot find an entry for #path#to#file.gcov in
+             .gcno file, skipping file!
+    
+    Avoid this warning by not filtering out non-instrumented lines.
+
+commit 37d381ae99a66f59ea55d966f1da13a726d2efe8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 5 15:09:58 2012 +0000
+
+    genhtml: fix source path prefix calculation
+    
+    Fix the following problems of the algorithm used to identify an
+    optimal source path prefix:
+    - the last two path components (filename and first parent
+      directory) are ignored when trying to identify the optimal
+      prefix
+    - if a path prefix matches a longer path prefix, the weight
+      of the filenames associated with the latter is incorrectly
+      attributed to the former
+
+commit 263de2b40e21193ef8d11e899eb55aa52b17225d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 5 12:00:57 2012 +0000
+
+    lcov: set default for branch coverage data to disabled
+    
+    Collecting branch coverage data can significantly slow down
+    coverage data collection and processing of data files. Assuming
+    that most users are more interested in line/function coverage,
+    change defaults to not collect/process branch coverage data.
+    
+    Users can still override this default using lcov_branch_coverage=1
+    in the lcovrc file or command line option --rc lcov_branch_coverage=1
+
+commit 7e04a152683ff66e24b87f2125474c6765d4524b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 5 11:49:30 2012 +0000
+
+    geninfo: fix problems with adjust_src_path option
+    
+    Fix the following problems with adjust_src_path:
+    
+     * specifying --compat libtool=on and geninfo_adjust_src_path
+       unexpectedly sets --compat libtool=off
+     * path components that are assembled from sub-directory names are
+       not correctly adjusted
+
+commit 74e4296b6e2a0b0f164c6828c28cc82449344f08
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 5 08:23:06 2012 +0000
+
+    lcov: add setting to disable function and branch coverage
+    
+    Add two new configuration file settings:
+    
+     * lcov_function_coverage and
+     * lcov_branch_coverage
+    
+    When set to zero, lcov will skip the corresponding coverage data
+    type from being collected or processed, resulting in reduced
+    memory and CPU time consumption and smaller data files.
+
+commit 37bc1a1a5f721c6b88fff4c63121c1cbb794c14f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Oct 2 14:29:57 2012 +0000
+
+    lcovrc: clarify meaning of geninfo_external in man page
+
+commit fc4b9e21efe8f3409d9b0b90cfe7a3e8bc59a74c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Oct 2 09:12:38 2012 +0000
+
+    geninfo: fix processing of pre-3.3 gcov files
+    
+    When trying to collect coverage data for programs compiled with
+    GCC versions prior to 3.3, geninfo skips each data file with the
+    following warning:
+    
+    geninfo: WARNING: cannot find an entry for test.c.gcov in .bb file,
+    skipping file!
+    
+    Fix this by deriving the source code filename from the gcov filename
+    in case the gcov files do not follow the GCC 3.3 format.
+    
+    Reported-by: georgysebastian@gmail.com
+
+commit d1014dfcabfee2f305278a14ec8e5343e3889139
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 24 11:43:18 2012 +0000
+
+    lcov: fix problems with --rc option
+    
+    Fix error "Invalid option linkage for \"rc=s%\"" when running lcov
+    with an older version of the Getopt::Long module. Also pass --rc
+    options through lcov to geninfo.
+
+commit a9f08b79e2e7ec2b4a5c9ad27a077df8dfb46890
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jul 24 15:41:38 2012 +0000
+
+    geninfo: implement rc option geninfo_adjust_src_path
+    
+    Provide a new lcovrc file option geninfo_adjust_src_path that users
+    can use to change incorrect source paths.
+    
+    Inspired by patch by ammon.riley@gmail.com.
+
+commit 108f805788590defda99fdf252bfb71cb749f31e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Jul 19 13:12:35 2012 +0000
+
+    lcov: implement command line option --rc
+    
+    Users can now use command line option --rc to override configuration
+    file directives.
+
+commit eeeeeca74706e88a9b8ecfef2bb3451957512e20
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 18 12:56:21 2012 +0000
+
+    lcovrc: add description for geninfo_compat setting
+
+commit f842e46149b48ff316e80f68f630bf94085e4d19
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 18 12:40:56 2012 +0000
+
+    lcov: improve --compat description
+
+commit 392a690ba31092857f7d21d0008783d87954ebce
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 18 12:13:00 2012 +0000
+
+    lcov: add missing documentation for --compat option
+    
+    Add missing sections in the geninfo and lcov man-pages for the
+    newly introduced command line option --compat. Also set the
+    default value for the hammer compatibility mode to 'auto' to
+    keep the behavior of previous releases.
+
+commit 691cab3e3aaebc295c2cfe91c43c6a7c48f1ec2b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 18 10:40:12 2012 +0000
+
+    lcov: fix extra closing parenthesis in comment
+
+commit cef6f0ff8baa9b2b3dfb437463e7a88d3380b555
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jul 17 11:37:13 2012 +0000
+
+    lcov: make 0%/100% exclusive to no/full coverage rate
+    
+    Ensure that coverage rates 0% and 100% are only used when no or all
+    lines/functions/branches are hit respectively. This approach is
+    implemented to allow better identification of boundary cases, and
+    to be in accordance with the behavior of the gcov tool.
+    
+    Based on suggestions by: Paul.Zimmermann@loria.fr and
+    vincent@vinc17.net
+
+commit 9cec8f7e332258c9128f1c53d61acb9f0bc17085
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 11 14:09:27 2012 +0000
+
+    geninfo: more improvements to the .gcno format auto-detection
+    
+    Suggestions by garnold@google.com:
+    - rename command line setting
+    - simplify logic
+
+commit 0bbca3bd0c1ad3e3d3fd0b6eebfc3afbbc212a85
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jul 6 14:29:27 2012 +0000
+
+    geninfo: rename compatibility setting to compatibility mode
+
+commit f30fb978662996e29517c733218292a91f5fd12b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jul 6 09:03:27 2012 +0000
+
+    geninfo: improve detection of gcc 4.7 function records
+    
+    Suggestions by garnold@google.com:
+    - perform detection only once
+    - add warning in case detection is off but overlong strings are found
+    
+    Misc:
+    - add help text for --compat
+    - isolate detection heuristic into separate function
+    - rename corresponding compatibility setting to "gcc_4_7"
+    - allow "android_4_4_0" as alias for "gcc_4_7"
+
+commit 01321c3f170e5d24ffb3bb998441c99f5b775836
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 4 16:06:10 2012 +0000
+
+    geninfo: enable auto-detection of gcc-4.7 function record format
+    
+    gcc-4.7 introduced a modified function record format. This format
+    is in use by android toolchains and has also been ported to some
+    pre-4.7 versions of gcc. Introduce a heuristic-based auto-detection
+    to correctly handle .gcno files in these cases.
+
+commit d929600a0e2133168085e5ddea7ee832afd902b7
+Author: Martin Hopfeld <martin.hopfeld@sse-erfurt.de>
+Date:   Fri Jun 8 14:19:49 2012 +0000
+
+    geninfo: Make geninfo work more reliably on MSYS
+    
+    Using the lcov tools on Win7 with MSYS and MinGW 4.5.1/4.5.2
+    raised some issues for us:
+    
+    geninfo created in the for one source file in the 'SF:' line
+    paths starting with a lowercase drive letter and sometimes
+    starting with uppercase drive letters.
+    
+    This lead to inaccurate coverage results on the MSYS platform.
+    
+    This patch fixes this issue.
+
+commit 5b2751854aa19e6443fdc5fecc139595988d1e99
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon May 7 16:04:49 2012 +0000
+
+    lcov: add perl version dependency to RPM spec file
+    
+    lcov CVS (1.10 pre) seems to be broken on MSYS with perl 5.6.1.
+    The issue is the following:
+    
+      genhtml: Unknown open() mode '>>&' at /usr/bin/genhtml line 5512.
+    
+      $> perl genhtml --version
+      genhtml: LCOV version 1.10 pre (CVS 1.58)
+    
+      $> perl --version
+      This is perl, v5.6.1 built for msys
+    
+    Fortunately perl v5.8.8 is available for MSYS and genhtml works like a
+    charm with that 'new' version.
+    
+    Reported-by: Martin Hopfeld <martin.hopfeld@sse-erfurt.de>
+
+commit 83957a145d243cad0f8060e4a9ccc6cb8ed8fc09
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Apr 10 11:48:52 2012 +0000
+
+    geninfo: add support for gcc 4.7 .gcno file format
+    
+    Based on patch by berrange@redhat.com.
+
+commit 91c91dbc63d1e880d106919300c2fb37737697b0
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 20 11:53:57 2012 +0000
+
+    lcov: add new command line option --compat
+    
+    Add new option to lcov and geninfo to specify compatibility settings.
+    
+    Supported settings:
+      libtool: same as --compat-libtool
+      hammer: gcc3.3 hammer patch compatibility
+      android_4_4_0: android toolchain 4_4_0 compatibility
+
+commit 9588355790a302da680eff2f664058f78439a03e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 11 08:29:21 2011 +0000
+
+    lcov: fix problem with Objective-C functions
+    
+    Fix geninfo not recognizing function entries for Objective-C functions.
+    
+    Based on patch by abrahamh@web.de:
+    current version of lcov unfortunately not support Objective-C files.
+    In details the count of tested function is zero always and the annotated
+    lines have an offset by one if the Objective-C method have one ore more
+    arguments.
+
+commit e1acd78d1e88fe51aad96badf32555c470ee029b
+Author: Martin Hopfeld <martin.hopfeld@sse-erfurt.de>
+Date:   Mon May 23 08:03:13 2011 +0000
+
+    geninfo: Make geninfo handle MinGW output on MSYS.
+    
+    This patch converts path mixtures from MinGW when running on MSYS to
+    correct MSYS paths.
+    
+    In solve_relative_path() an additional conversion step will be inserted
+    when running on MSYS. This will extract the drive letter and convert the
+    remaining path from Windows pathnames to Unix Paths, which are used by
+    MSYS.
+    
+    Additionally, if no drive letter is found, the (relative) path is
+    converted to Unix style. There may be the case where Windows and Unix
+    path separators are intermixed within one path string.
+
+commit ed161e3db5cd5a7c6c8b2113930c729f001cdd4e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Dec 16 08:11:22 2010 +0000
+
+    genpng: handle empty source files
+    
+    Generating an overview PNG image for an empty source code file fails.
+    Handle this case by assuming a single empty line when run for an empty
+    source code file.
+    
+    Reported by: sylvestre@debian.org
+
+commit 95e2c5c337d281b4e88144d95d29bbec183c8728
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Dec 7 08:40:09 2010 +0000
+
+    genhtml: add note to further explain branch coverage output
+
+commit b1c66916151dd4b20998c79f81edf174659ebb14
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Dec 7 08:29:45 2010 +0000
+
+    genhtml: fixed incorrect description of default coverage rates
+
+commit 1994be7d8ed472772b884063af74235f2f25ab39
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Nov 19 16:33:25 2010 +0000
+
+    geninfo: add missing man page sections
+    
+    Add sections describing options --derive-func-data and --no-markers to
+    the geninfo man page.
+
+commit 01a393ef76092e43ebd2d8bf7892ebf375481a84
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Nov 19 16:15:27 2010 +0000
+
+    geninfo: remove help text for unimplemented parameter
+    
+    Parameter --function-coverage was removed but the help text still
+    mentions it. Fix this by removing the option from the help text as
+    well.
+
+commit b92f99d9db0af131080c462300dc9baf292a8ff6
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Nov 19 16:00:22 2010 +0000
+
+    genhtml: handle special characters in file and directory names
+    
+    HTML special characters (e.g. '<') found in file or directory names are
+    not correctly shown in HTML output. Fix this by correctly escaping such
+    characters.
+
+commit 17e158d4569d25218e79901e2d8cd03bfc7752fc
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Nov 19 15:45:01 2010 +0000
+
+    gendesc/genhtml/geninfo/genpng/lcov: handle '<' in filenames
+    
+    Use 3-arg open mode to prevent that a special character (e.g. '<')
+    found in a user-specified filename interfers with the required open
+    mode for that file.
+
+commit b87e40e475c560bdc88206df4de6dc8cf094d91f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Nov 19 15:11:53 2010 +0000
+
+    geninfo: ignore <built-in>.gcov files
+    
+    The gcov tool will sometimes create a file <built-in>.gcov for code
+    which was added by gcc itself during compilation. Since there isn't
+    any source available for such code, geninfo will fail. Fix this
+    by skipping these files while capturing code coverage data.
+
+commit 398d8f385423927b5675c1429f58c67b6a89a1a8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Oct 28 14:17:57 2010 +0000
+
+    geninfo: add function comment
+    
+    Add comment explaining data structures used by function derive_data.
+
+commit f5c2072e0e7195d35455db50705884e7f6c5fbe5
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Oct 28 14:16:34 2010 +0000
+
+    geninfo: apply exclusion marker to derived function data
+    
+    When option --derive-func-data is used together with exclusion markers,
+    function data for excluded lines is still included. Fix this by
+    only deriving function data for lines which are instrumented and not
+    excluded.
+    
+    Reported by: bettse@gmail.com
+
+commit 82280b8a5a78e8a147c333c8850a556729d9d96d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Aug 31 08:19:03 2010 +0000
+
+    geninfo: improve --debug output
+
+commit 6375a03010cb1bb22490b9d19a176188940e2f8b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Aug 31 08:17:23 2010 +0000
+
+    gcov: add configuration file option to not use gcov's -a option
+    
+    lcov calls gcov while specifying its --all-blocks option to get more
+    detailed branch coverage data per line. It turns out that this option
+    is broken on many versions of gcov, resulting in an endless loop while
+    processing some gcov data files. There's also a slight performance
+    penalty when specifying -a.
+    
+    lcov users can opt to not use the -a option by setting configuration
+    option geninfo_gcov_all_blocks to 0 in the lcovrc file.
+
+commit 7706fb73ebef8060fbbd92c0e08b5d68a2cd284e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Aug 24 16:15:53 2010 +0000
+
+    lcov: add option to specify a configuration file
+    
+    Provide an option for users to specify a configuration file to lcov.
+    This option may be useful when there is a need to run several instances
+    of a tool with different configuration file options in parallel.
+
+commit a404dafc2da12608a936afeb095d68410fa49b0a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Aug 23 16:14:37 2010 +0000
+
+    lcov: add option to display summary coverage information
+    
+    Provide an option for users to determine the summary coverage
+    information of one or more tracefiles. Example output:
+    
+    Summary coverage rate:
+      lines......: 26.0% (78132 of 300355 lines)
+      functions..: 34.9% (8413 of 24081 functions)
+      branches...: 16.9% (32610 of 193495 branches)
+
+commit 526b5b6a43f2b29f11eb02c1dd8f645293d8c295
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Aug 23 14:47:43 2010 +0000
+
+    lcov: add option to exclude external files
+    
+    Implement an option for users to specify that external source files
+    should be excluded when capturing coverage data. External source files
+    are files which are not located in the directories specified by the
+    --directory and --base-directory options of lcov/geninfo.
+
+commit c2255a0344648dc6eaef0189c53f345fdc70ed4e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 20 14:58:48 2010 +0000
+
+    lcov: pass --no-recursion to geninfo
+    
+    When specifying --no-recursion, make sure that the option is also passed
+    to the helper tool geninfo.
+
+commit 83543f3d21b5a5496b57c8d73e8e9c1819f82f34
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 20 14:31:59 2010 +0000
+
+    genhtml: fix HTML page title for directory pages
+
+commit b77df8ef1a69de3809e0b0bfa5cbbe5a84f313ae
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 20 14:27:19 2010 +0000
+
+    genhtml: make HTML charset specification customizable
+    
+    Provide a configuration file setting to adjust the charset specification
+    used by all generated HTML pages. Also change the default charset to
+    UTF-8.
+
+commit 1ff260462a67c440dc709d34c1fadf7d64760120
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 20 13:14:50 2010 +0000
+
+    lcov: follow Perl naming guidelines
+
+commit f637eb8c6ecb793b64eeb6bea57c6be8501d1484
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 20 13:08:25 2010 +0000
+
+    genhtml: add --ignore-errors option
+    
+    Provide a means for users to specify that genhtml should not abort if
+    it cannot read a source code file. Also make handling of --ignore-errors
+    parameter consistent accross lcov, geninfo and genhtml.
+
+commit 617bced393d5bb97e3409ec140768d9c8a2e2bfb
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 6 11:25:12 2010 +0000
+
+    lcov: update CVS version to 1.10
+
+commit 4dcb4f0ed014ca0f49859ef84fc9ced650f6deb8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 6 11:14:38 2010 +0000
+
+    lcov: finalizing release 1.9
+
+commit 594779e047eed2f534905ac40912969955d3797f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 5 16:17:44 2010 +0000
+
+    lcov: update CHANGES file in preparation of new release
+
+commit fbbd9034e7a4ea4bc59342b22bfbe9612dd4bdb8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 5 15:11:56 2010 +0000
+
+    lcov: introduce configuration file parameters for list output
+    
+    Make some aspects of list output customizable via configuration
+    file parameters. Also introduce special handling, if the root
+    directory is chosen as prefix.
+
+commit c6e783c1a1d3fb6db7419af95f9e2dcb89836fe9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 5 14:07:35 2010 +0000
+
+    lcov: switch coverage rate and number columns in list view
+    
+    To be more consistent with the order of output in the "Overall
+    coverage rate" case, rates are now shown first in the list output.
+
+commit 3c87b66c68c2e06811c9be479c6813cb409e5461
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 5 11:22:12 2010 +0000
+
+    lcov: fix display of total line coverage rate in list view
+
+commit 3cb6bc4ae0ef34aa63931d63f659f1ef43804c77
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Aug 4 16:15:19 2010 +0000
+
+    lcov: more lcov --list improvement
+    
+    Further improve list output to increase readability.
+
+commit dd98ff68ad143b985a728fc585c86d69e6027bd8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 28 14:49:47 2010 +0000
+
+    lcov: minor list improvement
+
+commit d4778c75ce8cf3c9d44607b6fd0e385db71126dd
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 28 14:48:25 2010 +0000
+
+    geninfo: remove unneeded functions
+
+commit 65a15afef3430c49c9c7c0d151cc2afec5fc83cc
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 28 14:19:09 2010 +0000
+
+    geninfo: print note on branch coverage data only once
+
+commit bd8ab633298ec27acf5f7db4b2cc4766baf1f153
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 28 14:17:59 2010 +0000
+
+    geninfo: remove incorrect overall coverage rate calculation
+    
+    geninfo output showing the overall coverage rate of its current
+    operation is incorrect since it may count lines, functions and
+    branches for included files multiple times. Remove the output
+    and associated code until a fixed version is available.
+
+commit 8c54de96a1326b7ee0632773816c52eda43393e8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 28 13:56:26 2010 +0000
+
+    lcov: more list output fixes
+
+commit 7e5fa9900d991320677c381db747c764495b2cc2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 28 13:52:01 2010 +0000
+
+    lcov: fix list output
+    
+    Fix list output for directories with short filenames.
+
+commit badd4790c70bd8ef8b991a9d56d0e062b28006a8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 26 13:33:18 2010 +0000
+
+    lcov: fix problem when using --initial and --kernel-directory
+    
+    Fix a problem in lcov that resulted in --kernel-directory options
+    being ignored when specifying --initial at the same time.
+    
+    Reported by hjia@redhat.com.
+
+commit a06c2038babb2f6d3e0a634cd298b0434041f834
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 19 16:06:15 2010 +0000
+
+    genhtml: change wording for branches which were not executed
+    
+    Since gcov sometimes reports both branches which were never executed
+    as well as branches which were executed in a single block, the wording
+    of the HTML alt text needs to be adjusted accordingly.
+
+commit e6b2491823ffd84c85406145031646af675170ee
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 19 15:50:02 2010 +0000
+
+    geninfo: handle branches in unnamed blocks
+    
+    gcov will sometimes report branches outside of a block. In that case,
+    account these branches to a special block so that they are not
+    accidentally merged with subsequently reported blocks.
+
+commit d6c82edf2117ce8b6232c998baf06c7a87269081
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 19 15:23:10 2010 +0000
+
+    genhtml: fix branch formatting code
+    
+    Fix the vertical alignment of the HTML representation of branches in
+    the source code view.
+
+commit 44ac74a47e25064ad1b421f65a28d057fdb9925d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 19 14:27:08 2010 +0000
+
+    lcov: improve list output
+    
+    Improve list output by separating directory and file names. Also provide
+    an option to show full path names.
+
+commit 0ab6f7507f3c4f074bec41e571ff1afbeb943185
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 19 12:12:43 2010 +0000
+
+    genhtml: fix large numbers being shown as negative in html output
+    
+    genhtml uses a "%d" format string for printing execution counts. For
+    counts exceeding integer range, the output becomes negative. Fix this
+    by using the "%.0f" format string instead.
+    
+    Reported by kkyriako@yahoo.com.
+
+commit bbf0ef40a51dd716c544f91576cffde7986bb6ec
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jun 7 12:22:18 2010 +0000
+
+    geninfo: ensure that exclusion markers apply to --initial
+    
+    Fix a problem where exclusion markers are ignored when gathering
+    initial coverage data.
+    
+    Problem was reported by ahmed_osman@mentor.com.
+
+commit b371fc59fa52f7176f62f382457fba498f39f4b2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jun 1 13:48:29 2010 +0000
+
+    lcov: fix problem with relative path names
+    
+    Fix a problem where coverage data is missing because gcov produces
+    output files starting with a dot.
+    
+    Problem reported by weston_schmidt@open-roadster.com.
+
+commit 93c70ddd0edbc2b0addf9d135dfd76871cc7a160
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Sun Feb 28 20:57:37 2010 +0000
+
+    lcov: fix problem with relative paths in build paths
+    
+    When binaries are built using relative paths, lcov cannot find any
+    coverage data. Instead, warnings similar to the following are printed:
+    
+    geninfo: WARNING: cannot find an entry for ^#src#test.c.gcov in .gcno
+    file, skipping file!
+    
+    The reason for this is that File::Spec::rel2abs does not remove ../ from
+    paths which results in lcov not being able to match the relative and
+    absolute versions of the corresponding filenames. Fix this by using the
+    internal function solve_relative_path instead.
+
+commit fad24a75cc69364d002d40e4fb75736b0efbdb37
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Sun Feb 21 14:57:52 2010 +0000
+
+    geninfo: write all debugging output to STDERR
+
+commit c0943385fa0acb927f63f9f78c9aeaebe3a8ece1
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Sun Feb 21 14:56:46 2010 +0000
+
+    geninfo: fix problem with some .gcno files
+    
+    Some .gcno files contain more data in a line record than
+    expected. Skip unhandled bytes of a .gcno file record.
+    This prevents the following unexpected error message:
+    
+    geninfo: ERROR: file.gcno: reached unexpected end of file
+
+commit 4b9ee7598e991b503425148eb43a35de2702aded
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Sun Feb 7 13:07:09 2010 +0000
+
+    lcov: add COPYING file
+
+commit de0e43a098ade45d6624ea43a53e6fad9a176469
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 11:07:25 2010 +0000
+
+    lcov: update CVS version to 1.9
+
+commit 4a33269fa3a73ea2577f7616d90bd3f1d14ae460
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 10:09:53 2010 +0000
+
+    lcov: finalizing release 1.8
+
+commit 310ffb28d8847f96e02b5a5db3d16bdcb406a876
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 10:01:35 2010 +0000
+
+    lcov: updated CHANGES file
+
+commit 9e12808e6108e05dca42b5e682bd8be121f3608d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 09:21:22 2010 +0000
+
+    genhtml: use sans-serif font for function table
+
+commit 71baabb6a1c15228213f8b25359346ee202300ce
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 09:12:55 2010 +0000
+
+    lcov: improve list output
+
+commit cc61a28dbc3c46ac84340141fafbfa559e1bf318
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 08:56:19 2010 +0000
+
+    lcov: fix overall rate display for tracefiles with more than one testcase
+
+commit b89028529db5110b3b76d117df788768a593d7dd
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 29 08:44:47 2010 +0000
+
+    lcov/genhtml: fix warning while merging branch data
+
+commit b7c69f31d9b1bfbd4bfc0fcb880cb8e514bcdb3f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Jan 28 15:59:23 2010 +0000
+
+    lcov: fix branch coverage related issues
+    
+    - warnings when combining certain combinations of branch data
+    - branches are not merged correctly when multiple input files are specified
+      to genhtml or when lcov -a is used
+
+commit 817875459df122fa3536a5e57c05ddfae19a089e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 27 16:37:50 2010 +0000
+
+    gendesc: fix problem with single word descriptions
+
+commit 33f60f48747b5ba12a6fdfb505bb662c922496bd
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 27 12:10:04 2010 +0000
+
+    lcov: remove temporary files when creating a package
+
+commit 6775457cbd3fa86acba4655d77b4ba2054b13253
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 27 12:00:05 2010 +0000
+
+    lcov: correctly retain information about converted test data
+
+commit f4d13eccc54f31a53ad109c3c4b86e4b52d6dfcb
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 27 10:17:43 2010 +0000
+
+    lcov. fixed overview output for function data
+
+commit aa00c65b7514c93320c1c787b848c8277593dcb0
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jan 26 09:36:19 2010 +0000
+
+    genhtml: don't use too much gcc-specific terms (basic block -> block)
+
+commit 3562f60b9500d8ad167c4629e9d95485308aa665
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:17:37 2010 +0000
+
+    lcov: consolidate coverage rate classification limits
+    
+    Classifying coverage rates per coverage type (line, function or branch
+    coverage) is not useful in most cases. Also the respective
+    color legend takes up too much space in the HTML output. Remove
+    function and branch coverage rates from the documentation and from
+    the color legend. Instead the original limits will be applied to those
+    coverage types as well. The per type rates can still be used if required
+    but it is recommended to only use one rate set.
+
+commit d77dc6a0adf259e322ac9f35c93241d446269a5b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:16:47 2010 +0000
+
+    lcov: minor code cleanup
+    
+    - remove unused function definitions and declarations
+    - remove unused CSS declarations
+    - add missing function declarations
+    - fix function prototypes
+
+commit b3243d1fdc17571ca9b1ed6a1ea975a9b3f1b86b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:16:15 2010 +0000
+
+    geninfo: consolidate similar functions
+
+commit 739e2bca054c69975594c2570049e8aa9ae1b5ce
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:15:35 2010 +0000
+
+    lcov: add coverage result output to more operations
+
+commit 0a31d3c0696015c5e4878e821529eba45451c3dd
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:14:57 2010 +0000
+
+    lcov: minor cosmetic HTML changes
+    
+    - top level view is now named "top-level"
+    - use sans-serif font for coverage values in file list
+    - use smaller font for show/hide details link
+    - use smaller font for function/source view link
+    - use smaller font for show descriptions link
+
+commit b631fa0cb9aabdf18f9365423f0b0bf85d6b8e16
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:14:27 2010 +0000
+
+    lcov: improve color legend
+    
+    Move color legend closer to the table containing coverage rates.
+
+commit 2aeeeafb31c36ccd1a51051f040e29a9fcf59df2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:13:58 2010 +0000
+
+    lcov: implement branch coverage
+
+commit 49dfe22f41b6c3edcb774dfb89b1a807ce7aee6c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:13:34 2010 +0000
+
+    genhtml: implement branch coverage
+
+commit 6aa2422401bb854c9710f5ed2936f06e487848c5
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:13:07 2010 +0000
+
+    geninfo: implement branch coverage
+
+commit ca2c9781b0a512bd6789eac2b6840405e2d87330
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 22 16:12:27 2010 +0000
+
+    geninfo: consolidate handling of extra gcov parameters
+
+commit 9d9c964eb6ece00b15ef068f176c68cb0eedfda0
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Jan 21 11:26:34 2010 +0000
+
+    lcov: minor fix for lcov --diff
+
+commit 4306f81d1e8446a89fe83d20cd71abe075a3cd61
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Jan 21 10:23:35 2010 +0000
+
+    lcov: improve lcov --list output
+
+commit 3242ce1bae94cfd859c3bc964fab11f85bd7d1ed
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 20 17:13:28 2010 +0000
+
+    lcov: unify data order in tracefiles
+
+commit 8f53b2e8dbbe5580050fbe0c604bd9a9322735a7
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 20 16:05:56 2010 +0000
+
+    lcov: fix bug when applying baseline files without function coverage data
+    
+    Fix the following error that occurs when genthml's --baseline-file option
+    is used on files which do not contain any function data:
+    
+    genhtml: Can't use an undefined value as a HASH reference at ./lcov/bin/genhtml line 4441.
+
+commit 96fcd676d5ac9c1eb9f83f3dc4c3089ba478baad
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 20 15:28:21 2010 +0000
+
+    lcov: resolve short-name option ambiguities
+
+commit f1d34d49b394a13c33c7a5b51f04e5dfbded5d26
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 20 14:47:50 2010 +0000
+
+    lcov: fix error messages
+
+commit 89ff61aa7cd2ca23b8cacd649288ecf7f67746de
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 20 08:35:20 2010 +0000
+
+    lcov: fix bug when using genhtml's --baseline-file option
+    
+    Fix the following error message when trying to use genhtml's
+    --baseline-file option:
+    
+    genhtml: Undefined subroutine &main::add_fnccounts called at
+    /home/oberpar/bin/genhtml line 4560.
+    
+    Reported by Brian DeGeeter <sixarm@gmail.com>
+
+commit c3df3a8504b06ca32b9863fdb2abb8cf0ce62251
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jan 18 09:17:17 2010 +0000
+
+    lcov: ensure LANG=C before calling gcov
+    
+    Fix problem calling lcov when LANG is not set to an english locale.
+    Reported by benoit_belbezet@yahoo.fr.
+
+commit d945f23345e02ca535d740782e7ae10cb3396b8c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Nov 18 09:39:21 2009 +0000
+
+    lcov: more version fixup
+
+commit 413249e6336cff432083954e6ed47236dd35f647
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Nov 18 09:38:03 2009 +0000
+
+    lcov: fix version fixup
+
+commit d0b7148e2d76164e5ea091fe56035c24f7dce22a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Nov 18 09:34:45 2009 +0000
+
+    lcov: add more CVS versioning
+
+commit 4e0219f918a15cbc9ff40d0e0e4dab91ac073f72
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Nov 18 09:14:56 2009 +0000
+
+    lcov: add CVS revision number to version output
+
+commit 34154c2d48497d9aad41ec1452ba94dd4cbce881
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 30 14:18:45 2009 +0000
+
+    lcov: further clarification in the README
+
+commit 7a4ab1340dd7f88ba0fb56a7b0eb368bf2d0112e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 30 13:58:56 2009 +0000
+
+    lcov: update README to mention required -lgcov switch during linking
+
+commit 3fa5b311b123af84debbd774baa4a1cd30e7085b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Oct 27 16:54:41 2009 +0000
+
+    lcov: remove further unneeded warning
+    
+    ... + use correct source for list of filenames
+
+commit cd4051719e72129f4abf1ad177269bf14031f83a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Oct 27 16:19:05 2009 +0000
+
+    lcov: fix problem with matching filename
+    
+    - used correct source for filenames
+    - converted match_filenames to portable version
+
+commit 0d0ff8a9945260eebed6d316aa08c0021faf3549
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Oct 27 15:29:41 2009 +0000
+
+    lcov: remove unnecessary warning
+
+commit 6c711d664c38d18f788ee8a5239586cd4a5b77d9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Oct 26 14:21:40 2009 +0000
+
+    lcov: improve derive-func-data option
+    
+    - rewrite graph file handling
+    - make derive data look at all lines belonging to a function to find
+      out whether it has been hit or not
+    - introduce --debug option to better debug problems with graph files
+
+commit 214cda20c4b591a823045f35b73f2a16221c9aa1
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Oct 1 15:26:58 2009 +0000
+
+    lcov: introduce new options --derive-func-data
+    
+    When using a gcov version that does not provide function data,
+    this option will attempt to guess the function coverage data
+    for a function by looking at the number of times that the first
+    line of that function was called.
+
+commit 9a75125895fd07a775a2a25f2cbe66b9fbf332d6
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Oct 1 11:49:53 2009 +0000
+
+    lcov: ignore incomplete function names in .bb files
+    
+    - don't abort processing when an incomplete function name is
+      encountered in a .bb file (gcc 2.95.3 adds those)
+    - fix filename prefix detection
+
+commit d5ab6076a0bfc5ad80652ba592583f7fc7946dc6
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Sep 28 12:27:09 2009 +0000
+
+    lcov: improve detection of gcov-kernel support
+
+commit 3cca782fcac9c4ea54adcebe75e1f047a8dca636
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Sep 22 13:44:04 2009 +0000
+
+    lcov: fix problem with CONFIG_MODVERSIONS
+    
+    Make geninfo work with Linux 2.6.31 and CONFIG_MODVERSIONS.
+
+commit 8af873f44c104cd214b796e13b916718fc8f6f99
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Sep 16 15:24:51 2009 +0000
+
+    lcov: remove default for gcov_dir so that auto-sensing works
+    
+    Fix problem with lcov not finding kernel coverage data at
+    /sys/kernel/debug/gcov because the default system-wide
+    lcovrc file contained a specification for the gcov directory
+    which prevented auto-detection from working.
+
+commit 50f90681af4d105a52b5b0dbf4f0bfd04369ffd2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 27 10:14:23 2009 +0000
+
+    lcov: apply excluded lines also to function coverage data
+
+commit 4aeb840d25c85a419171970e1a445aeb81079e53
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 27 09:23:13 2009 +0000
+
+    lcov: fix help text typo
+
+commit c17a783f87aa8e42949131d2fbc1c540bb3751a3
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 27 09:22:43 2009 +0000
+
+    lcov: add exclusion markers
+    
+    Users can exclude lines of code from coverage reports by adding keywords
+    to the source code.
+
+commit 445715c88337c13ce496bd05423ee5e58d84705c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 14 08:19:26 2009 +0000
+
+    lcov: ignore gcov errors for unnamed source files
+    
+    When specifying "--ignore-errors gcov", lcov/geninfo should not abort when
+    they cannot read a .gcov file. Fix this by introducing warnings in the
+    respective places.
+
+commit 0e23f03a9ce130e8ebec679fb5a9a6f854efbee5
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 6 12:34:04 2009 +0000
+
+    lcov: improvements
+    
+    - added --from-package and --to-package options
+    - improved gcov-kernel handling
+
+commit 17a05bdf646870cd61794274c7165211c93c82f9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Jul 23 12:45:15 2009 +0000
+
+    lcov: fix kernel capture for new gcov-kernel version
+    
+    - fix problems when compiling without O=
+
+commit 64e302b9134b6098852cad2e6180e0722f2dea41
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jul 21 15:42:44 2009 +0000
+
+    lcov: improve lcov -l output
+
+commit cea6941ef36d0860330b6e94f8c6096dca78ca58
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jul 21 09:10:49 2009 +0000
+
+    lcov: add support for the linux-2.6.31 upstream gcov kernel support
+
+commit 04470d2b25808f195d338112155b9f7db405d902
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Apr 22 09:13:12 2009 +0000
+
+    genhtml: fix warning about undefined value used
+    
+    nikita@zhuk.fi:
+    genhtml.patch checks that $funcdata->{$func} is defined before using
+    it - I got few "undefined value used" warnings without this check.
+
+commit a12d4f9a5d36232b928be12b7cbfaa9a00b3a923
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Apr 22 09:08:19 2009 +0000
+
+    genpng: fix runtime-warning
+    
+    - when called from within genhtml, genpng would warn about warn_handler
+      being redefined
+
+commit d0b5641c62bbdac89757b9ff185a7aa3f38fc0bb
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Mar 13 09:58:00 2009 +0000
+
+    lcov: improve function name filtering
+    
+    Only remove those characters from function names which would conflict
+    with internal delimiters.
+
+commit fbafa4a5628a639544e83f88083082c685677c36
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Feb 13 15:04:40 2009 +0000
+
+    genhtml: minor man page update
+
+commit 085a2150e38a3c1bdadb5af23c0a8a8a79dc4b0d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Feb 13 14:56:45 2009 +0000
+
+    genhtml: added --demangle-cpp option
+    
+    - used to convert C++ internal function names to human readable format
+    - based on a patch by slava.semushin@gmail.com
+
+commit 53f3ed4afb45a2a4248314b677d36377598cc73c
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Feb 13 14:07:46 2009 +0000
+
+    genhtml: update comment
+
+commit 3c2b2e8541387506fd514d183f9a4a63c07c0aa4
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Feb 12 17:01:19 2009 +0000
+
+    genhtml: fix error when combining tracefiles without function data
+    
+    - genhtml: Can't use an undefined value as a HASH reference at genhtml
+      line 1506.
+    - bug reported by richard.corden@gmail.com
+
+commit 22397370ada6893b6e9a1c3f6ad0aba7f4864f81
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Feb 11 09:31:24 2009 +0000
+
+    lcov: fix error when combining tracefiles without function data
+    
+    - lcov: Can't use an undefined value as a HASH reference at lcov line
+      1341.
+    - bug reported by richard.corden@gmail.com
+
+commit 24ec53ae83acdd35682ba757adae23750bd4c623
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Feb 9 16:15:49 2009 +0000
+
+    lcov: fix warning when $HOME is not set
+    
+    - based on patch by acalando@free.fr
+
+commit 5da3521d5a438db0a21e93b0d14ea5a3cdab14d9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Feb 9 12:41:44 2009 +0000
+
+    lcov: use install -pD -m <mode> for file installation
+
+commit bdce1bda2ac1a86aa6dfefae8e18353ba57afe4b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Feb 9 09:46:00 2009 +0000
+
+    lcov: fix double-counting of function data
+
+commit ea62c4e701abb05dd560ef22b52a4a72c17660e8
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 21 16:33:29 2009 +0000
+
+    geninfo: need to add CR removal to geninfo as well
+    
+    ... or checksumming will fail
+
+commit 70be5df7d58a393e27cee178df669c12ec670c5a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 21 16:24:01 2009 +0000
+
+    lcov: modify end-of-line CR removal
+    
+    - s///g is 10% slower than s/// - \r may be 0x10 or 0x13 (see man
+      perlport)
+
+commit d8df4b0f83ff175f1a06afb693903ee1a93ec377
+Author: Michael Knigge <michael.knigge@set-software.de>
+Date:   Tue Jan 20 11:41:39 2009 +0000
+
+    lcov: remove CRLF line breaks in source code when generating html output
+    
+    - added patch by michael.knigge@set-software.de
+
+commit 442cca7e69356e7f8ba03bd95f7813576bd197cc
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Nov 17 14:11:20 2008 +0000
+
+    lcov: updated CVS version to 1.8
+
+commit 5c5c85a1c090360facd50cb089b8af98f0b37c47
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Nov 17 13:55:52 2008 +0000
+
+    lcov: version + date updates
+
+commit 9f6a735809c23559b861e97a20af55a66b6b96bb
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Nov 17 13:49:43 2008 +0000
+
+    lcov: fix spec file bug
+
+commit 11483dc0b56d326718edcd31d06458143add858f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Nov 17 13:44:38 2008 +0000
+
+    lcov: update error and warning messages
+
+commit 4dd11b80d14e34fee2e75b3fe8c7aa163f61ad1d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Nov 17 12:48:03 2008 +0000
+
+    lcov: preparations for release 1.7
+
+commit b847ed6f3103a4c9f0a48417b9c3f160b9e00557
+Author: Jeff Connelly <jeffconnelly@users.sourceforge.net>
+Date:   Fri Oct 10 07:54:47 2008 +0000
+
+    lcov: geninfo chokes on spaces in the directory name
+    
+    In lcov 1.6, geninfo fails to find gcno/gcda files if the source directory
+    has spaces in the name, because it uses backticks to shell out to "find",
+    passing $directory on the command-line.
+    
+    Attached is a patch that double-quotes the variable, allowing geninfo to
+    operate on directories with spaces in their name. The fix isn't perfect; it
+    won't work on directories with a " character, but it works fine for my
+    purposes (I don't have any directories with quotes). A better fix would be
+    to use IPC::System::Simple's capturex from
+    http://search.cpan.org/~pjf/IPC-System-Simple-0.15/lib/IPC/System/Simple.pm
+    #runx(),_systemx()_and_capturex(). capturex() is a multiple-argument form
+    of the backticks, so it avoids any interpolation errors.
+
+commit ee3cdd554ee4e6d3ef5bdc9c5dcfee50de6375a7
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Aug 18 07:12:33 2008 +0000
+
+    lcov: change sorting order to low-to-high coverage
+
+commit fe665ca5ccf9d73d9ebdae17de88e181c1b9b0eb
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 15 08:38:21 2008 +0000
+
+    lcov: several changes
+    
+    - update download link
+    - unify webpage links
+    - provide --sort and --function-coverage switch + documentation
+
+commit 14137c5456f307982fed418e1e8fac65d7f086c3
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Aug 13 15:57:23 2008 +0000
+
+    lcov: fix function view page creation when --no-func is specified
+
+commit e59f7d15ffc7f1b3794a4212c53d0fb97ac7fb2a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Aug 13 15:35:48 2008 +0000
+
+    lcov: updated versioning mechanism
+    
+    ... + fixed some man page bugs
+
+commit e933698b31bc2fb4a750d89a5755bb8155313da2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Aug 13 14:08:23 2008 +0000
+
+    lcov: updated rpm description
+    
+    ... + summary and version strings
+
+commit 5a9660585ce39a77fa38607d0c2d2440955e7242
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Aug 13 13:53:50 2008 +0000
+
+    lcov: integrated function coverage patch
+    
+    ... by Tom Zoernen + sorting function
+
+commit d10ede8179747cfd675a3989578350c710e9bdd5
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed May 7 15:08:12 2008 +0000
+
+    lcov: --norecursion becomes --no-recursion
+    
+    + added docs
+
+commit 4096130608b9faf74c5b5feac554a10b5d9f83ce
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Feb 21 10:20:33 2008 +0000
+
+    lcov: fix error when trying to use genhtml -b
+    
+    genhtml fails when the data file contains an entry which is not
+    found in the base file.
+
+commit 9578099e13388344a6179c7cce54bfa094fd9b08
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Feb 20 17:21:51 2008 +0000
+
+    lcov: fixed problem with pre gcc-3.3 versions
+    
+    read_gcov_headers does not return valid results for pre gcc-3.3 versions.
+    Due to an unnecessary check, parsing of gcov files was aborted. Fix
+    by removing check.
+
+commit 16ec76b48fbc50c32890919e5bd0c30653719af9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Feb 5 09:18:50 2008 +0000
+
+    lcov: adding support for gzipped html
+    
+    ... based on patch by dnozay@vmware.com
+    
+    dnozay@vmware.com: genhtml is a great tool to generate html, but the more
+    files, the more space it takes (here I have over 113MB of html generated),
+    add to that I need to have different sets, and space usage increases
+    dramatically (2.7GB). we are using browsers with htmlz support, so it would
+    be nice to have support for that in genhtml, relying on 'gzip -S z' to do
+    the job.
+
+commit f2c98a8c8581180533508eb4af41720d8566049e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jan 7 16:33:57 2008 +0000
+
+    Filter non-word characters in function name
+    
+    ... as they would break our file format which uses comma and '=' as
+    field separator.
+
+commit 37725fc78fcacaf06e6240971edc3bdd7fe3d142
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Nov 1 16:29:39 2007 +0000
+
+    lcov: fix for problem resulting in lcov aborting with "ERROR: reading string"
+
+commit 48f13fcec1b521d2daba6202ccd7ec0ec8c5ece9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Oct 4 08:18:07 2007 +0000
+
+    lcov: workaround for gcc 4.1.0 .gcno file oddness
+    
+    scott.heavner@philips.com:
+    I'm trying to use lcov 1.6 with gcov/gcc 4.1.0. The geninfo parser was
+    aborting on a small number of .gcno files. I've patched my local copy so
+    that geninfo prints out the offset of the error and skips the remainder of
+    the problem file
+
+commit 1a805ea068db29b63a83c801f3bb1840fda8dd35
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 24 08:50:26 2007 +0000
+
+    lcov: add experimental option "--norecursion"
+
+commit 194de5071db1d9903d22164432448b73c1ec6cd0
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 23 11:08:39 2007 +0000
+
+    lcov: Makefile for post-release
+
+commit 0750f8a3e5235833711d616a3763c04103cf55a5
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Aug 23 11:04:30 2007 +0000
+
+    lcov: Makefile for release 1.6
+
+commit cb911f7a79593c89a730dc93fa54179fbf1df363
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Aug 20 10:29:35 2007 +0000
+
+    lcov: fixed spec file
+
+commit 62cefebdda87784140eb5f997ae4e575d2338298
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jul 6 07:38:47 2007 +0000
+
+    lcov: add new option --initial to get zero coverage data from graph files
+
+commit f0b6927f1ab1052b00081c662ced614a6e5f9ed7
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 4 14:38:59 2007 +0000
+
+    lcov: fixed bug that would not delete .gcda files when using -z
+
+commit 13941c3a159caf7dc6ba18a5b13e43c20fc18f2b
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 4 14:18:26 2007 +0000
+
+    lcov: another update in preparation for a new release
+
+commit d25e630a77ef2d0f69139058322269387866e414
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jul 4 13:13:22 2007 +0000
+
+    lcov: man page update
+
+commit 7844b915af5402441df9ab0423e4c20ef9a2632f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jul 3 16:43:05 2007 +0000
+
+    lcov: update manpage
+
+commit 5adaa72bfb32737d18c328492777c1c6116d4a9e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jul 2 15:29:02 2007 +0000
+
+    lcov: preparations for new release
+    
+    - updated CHANGES file
+    - added compat-libtool + no-compat-libtool option
+    - changed libtool default to on (due to popular request)
+    - added checksum option
+    - changed checksum default to off (to reduce cpu time + file size)
+    - added geninfo_checksum option to lcovrc, deprecated
+      geninfo_no_checksum
+    - added geninfo_compat_libtool option to lcovrc
+    - minor update of README file
+
+commit 6cbfd5022703a6198e1a1e2a2ddddcc0b90f5334
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue May 22 08:11:44 2007 +0000
+
+    lcov: minor help text update
+
+commit 2416ed02ba299c4d0bceb1e47c214b7dec066d7a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Mar 7 14:59:25 2007 +0000
+
+    lcov
+    
+    - add --ignore-errors option to lcov/geninfo
+    - add --gcov-tool option to lcov/geninfo
+    - remove s390 test case modification in geninfo
+    - restructured help text for lcov/geninfo
+
+commit a13375811717d3ada718e6f52364e4344a7e3187
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jan 8 17:07:21 2007 +0000
+
+    lcov
+    
+    - re-added libtool compatibility workaround patch by
+      thomas@apestaart.org
+    - added new lcov/geninfo-option --compat_libtool to activate libtool
+      compatibility patch
+
+commit 14871d7b097282819db60266d8b8a38506d7b14a
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Nov 14 11:45:17 2006 +0000
+
+    lcov
+    
+    Fix for problem found by Joerg Hohwieler: lcov -k doesn't work if -k is
+    specified more than once.
+
+commit 43b52b37006822c0fca12548bc72fecc957342ca
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Jun 26 15:48:52 2006 +0000
+
+    lcov: new version for prerelease rpms
+
+commit 89e9d59709c9d9d8722170c86251090adc3b96c9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jun 7 09:31:57 2006 +0000
+
+    lcov: removed autoupdate of copyright date (second thoughts)
+
+commit bb0cf1c9d0ed58b37c1551fea765fb1622bcacde
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jun 7 09:20:37 2006 +0000
+
+    lcov: minor cleanup (release preparations)
+
+commit 527693d753d11ac2b59fe26b923662c99e6e3715
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Apr 5 10:10:05 2006 +0000
+
+    lcov
+    
+    - added base-directory documentation
+    - updated CHANGES file
+
+commit 11ef9338cc4124801c8b61e3edd51a02e50b4c68
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Mar 20 17:09:50 2006 +0000
+
+    genhtml: added html-extension option
+
+commit 93d22308ffb410327248059b7dcdb592f85e249e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Mar 20 16:39:25 2006 +0000
+
+    genhtml
+    
+    - adding html-prolog and html-epilog options (based on patch by Marcus
+      Boerger)
+    - specified behavior when both --no-prefix and --prefix options where
+      provided
+    - small whitespace diff
+
+commit dcac095cdc00cc65930285bb6fc01d0f257ee4ed
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Feb 15 16:02:07 2006 +0000
+
+    lcov: added check for invalid characters in test names
+
+commit d89e561dfd9c5fde43350af1b145b1892d0710d0
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Dec 2 06:38:16 2005 +0000
+
+    lcov
+    
+    - updated Makefile so that people building RPMs from the CVS version get
+      a correct build version. Note: this needs to be adjusted after each
+      release!
+
+commit 1960123050f9098690768d10cd2490dd49b995f7
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Thu Nov 10 13:10:09 2005 +0000
+
+    lcov
+    
+    - fixed bug: .info file generation with new gcc 4.x compilers may fail
+      for programming languages that allow ':' in function names (c++,
+      objective c)
+    - removed special handling for libtool .libs files
+    - libtool should work with currently undocumented option --base-directory
+
+commit 479d446d3bf20a84c2933100ead279c79eeaf5c4
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Sep 7 16:24:39 2005 +0000
+
+    lcov
+    
+    - implementation of new option --base-directory (untested, undocumented)
+    - minor fix for link-traversal when looking for object directory
+    
+    TODO: document option (man page, online help), add to config file, check
+    whether libtool fix still works
+
+commit 770b94a3172f206de7f194c7497ebae14348b521
+Author: Robert Williamson <robbiew@users.sourceforge.net>
+Date:   Mon Jul 11 17:54:25 2005 +0000
+
+    Applied patch from Stefan Kost
+    
+    when running lcov over an uninstalled user-space apps tests, it finds
+    the .da file in the .libs directories, but does not look for the sources
+    one hierarchy up. Libtool places the object in the .libs dirs. when
+    running gcov manually one can specify -o.libs/ to produce a source.c.gov
+    file. I now have attached a patch that fixes the problem for me. please
+    do not just ignore this report. the lcov tool is so nice and it would be
+    a shame if it can not be used for normal apps.
+
+commit 79f2ff2c168150e7532046c2cdbc1e42c8b4708f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Jun 14 11:34:59 2005 +0000
+
+    lcov
+    
+    - renamed support for modified compilers (gcc 3.3 hammer patch)
+    - fixed bugs in the support for modified compilers
+
+commit fb7dab3494fdd8b093e6a84f088f6ea07fcefe6e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Mar 15 18:02:54 2005 +0000
+
+    lcov
+    
+    Emil.Jansson@oss.teleca.se:
+    lcov 1.4 does not work with the gcc version in Mandrake Linux 10.0
+    
+    >> gcc --version
+    
+    gcc (GCC) 3.3.2 (Mandrake Linux 10.0 3.3.2-6mdk)
+    
+    This patch for geninfo fixes the problem:
+
+commit ae3fe899d824e8af8a16736a0c8104c903565a56
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Mar 8 14:23:06 2005 +0000
+
+    lcov
+    
+    - added optional legend to HTML output
+    - changed background color for "good coverage" entries to green for
+      consistency reasons
+
+commit 18b73d39fd9d6bc8829395baa612a6ed98b89efe
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Mar 2 14:49:47 2005 +0000
+
+    lcov
+    
+    - fixed rpm build process to exclude unnecessary directories in RPM
+
+commit ef6ee74df5bf1d1d104322f8fff36b5c6fda34b4
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Mar 2 12:48:29 2005 +0000
+
+    lcov
+    
+    - added man page for configuration file lcovrc
+
+commit be3afe2626d6bc72256e1873d409c737ac4391c9
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Feb 28 16:31:51 2005 +0000
+
+    lcov
+    
+    - Updated CHANGES file in preparation for a new release
+
+commit dc68ce9c804ef21bc8e149d9b468e18c1619bb54
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Nov 2 15:48:45 2004 +0000
+
+    lcov
+    
+    - temporary fix for a problem which occurs when trying to parse C++
+      coverage data generated with vanilla gcc 3.3.3
+
+commit efedc5b930ab6743ea9f47ce4ea4a1a75bd739ff
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Sep 27 13:13:51 2004 +0000
+
+    lcov
+    
+    - fix for minor bug in geninfo (access to uninitialized variable)
+      related to SLES9 compatibility test and test for existing source code
+      files
+
+commit 47943eedfbec7a12c52e7a8ccbcfaf8d0706f142
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Sep 20 14:11:16 2004 +0000
+
+    lcov
+    
+    - minor fix for regular expression used to parse .gcov files - caused
+      problems when parsing branch coverage data and when using custom
+      gcov versions
+
+commit ce6335ebd92ce017b75ee3e194e9e3ca7bc7e1f3
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Sep 14 15:52:38 2004 +0000
+
+    lcov
+    
+    - fixed bug in geninfo which would not report any FN: data for data
+      generated with gcc versions 3.4.0 and above
+
+commit 58df8af3a62fa4e60569ef300e0ddd0073bf109e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Aug 31 15:57:41 2004 +0000
+
+    lcov
+    
+    - added support for modified GCC version provided by SUSE SLES9
+
+commit 69f3bc3a0c59b35eb6882205286a68b04a8a8d22
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Aug 31 15:48:32 2004 +0000
+
+    lcov
+    
+    - fixed bug in lcov RPM spec file which would not include the global
+      config file in the package list
+
+commit 5d10ca22144ad2be885405c3683b20c0976f7562
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Aug 9 14:32:23 2004 +0000
+
+    lcov
+    
+    - fixed a bug which would cause generation of incorrect line checksums
+      when source code is not available while capturing coverage data
+    - changed default directory for temporary files from . to /tmp
+
+commit 8ee3061f23f17a5074deda0777c66c3e82b5d852
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Aug 9 11:15:02 2004 +0000
+
+    lcov
+    
+    - added configuration file support
+    - fixed Makefile error for target "uninstall"
+
+commit 58af07f0b0ca1af8c9f2b90ad1683447bb560165
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Aug 6 11:36:33 2004 +0000
+
+    lcov
+    
+    - fixed bug which would cause an error when lcov was used on a source
+      directory which contained perl regular expression special characters
+    - simplified regular expression character escaping
+    - removed unnecessary function escape_shell from lcov
+
+commit 69a6918d4cd386aff2fbff093a6e0b5ddcc46602
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Mar 30 13:27:55 2004 +0000
+
+    lcov: - added --path option to fix --diff functionality
+
+commit cbc6cb11b532e525ae8b0c0742a4fd41189ca7c2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Mar 29 12:56:08 2004 +0000
+
+    lcov
+    
+    - Added compatibility for gcc-3.4
+    - Modified --diff function to better cope with ambiguous entries in
+      patch files
+    - Modified --capture option to use modprobe before insmod (needed for
+      2.6)
+
+commit 1cf9a02c3ea0e98cc1d8b626eaa0a2a1cbd96cf1
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Jan 30 09:42:13 2004 +0000
+
+    lcov
+    
+    - updated CHANGES file
+    - changed Makefile install path (/usr/local/bin -> /usr/bin)
+
+commit c60f0668059032cf4dc5f6c556fd6117925f535f
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Jan 14 10:14:10 2004 +0000
+
+    lcov-patch by Laurent Deniel
+    
+    avoids aborting the geninfo processing when an empty .bb file is
+    encountered (e.g. source code with no profiled statement)
+
+commit 7f2966f8f874a6c905b4d31e5aaf0f4654929044
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Dec 19 16:22:52 2003 +0000
+
+    lcov: updated references to lcov webpage to reflect recent site changes
+
+commit a3893f4eb2b4fadc4d7350324d74fa453a5ba0f3
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Dec 19 12:50:28 2003 +0000
+
+    Added changes by Laurent Deniel
+    
+    - a small patch to lcov 1.1 that introduces the --follow option (in
+      lcov & geninfo) to control whether or not links should be followed
+      while searching for .da files.
+    - a workaround for a gcov (3.2) bug which aborts with empty .da files
+      (gcov 3.3 is fixed but many distributions include gcc 3.2)
+
+commit d44f2f8e8672e31cc104c0598b0556a5949dc067
+Author: Paul Larson <plars@users.sourceforge.net>
+Date:   Fri Nov 21 19:34:59 2003 +0000
+
+    Fixed two buglets that caused geninfo to break with some versions of gcov.
+    
+    1. Return value for gcov --help might not be 0, expect -1 when it
+       doesn't exist
+    2. use -b instead of expanded (--branch-coverage or whatever it was)
+
+commit 5a1a33a840a665c77409f799be91cc2dce5cd3b2
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Tue Nov 18 14:06:47 2003 +0000
+
+    lcov
+    
+    - fixed function which interprets branch possibility data in geninfo
+      (branch x taken = y% would not be interpreted correctly)
+    - deactivated function which would add 'uname -a' output to testname
+      in geninfo (output in genhtml/showdetails looked unreadable, there
+      needs to be some better solution)
+
+commit e0ea03fedf43a3232c35708f882d7058998b2b3d
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Oct 10 14:18:32 2003 +0000
+
+    New function and bug fix update.
+    
+    Makefile:
+    - Added rule to build source rpm
+    
+    lcov.spec:
+    - Modified to support building source rpms
+    
+    genhtml:
+    - Fixed bug which would not correctly associate data sets with an empty
+      test name (only necessary when using --show-details in genhtml)
+    - Added checksumming mechanism: each tracefile now contains a checksum for
+      each instrumented line to detect incompatible data
+    - Implemented new command line option '--nochecksum' to suppress generation
+      of checksums
+    - Implemented new command line option '--highlight' which highlights lines of
+      code which were only covered in converted tracefiles (see '--diff' option of
+      lcov)
+    
+    geninfo:
+    - Added checksumming mechanism: each tracefile now contains a checksum for
+      each instrumented line to detect incompatible data
+    - Implemented new command line option '--nochecksum' to suppress generation
+      of checksums
+    - Added function to collect branch coverage data
+    
+    lcov:
+    - Fixed bug which would not correctly associate data sets with an empty
+      test name (only necessary when using --show-details in genhtml)
+    - Cleaned up internal command line option check
+    - Added info() output when reading tracefiles
+    - Added checksumming mechanism: each tracefile now contains a checksum for
+      each instrumented line to detect incompatible data
+    - Implemented new command line option '--nochecksum' to suppress generation
+      of checksums
+    - Implemented new command line option '--diff' which allows converting
+      coverage data from an older source code version by using a diff file
+      to map line numbers
+    
+    genpng:
+    - Added support for the highlighting option of genhtml
+    - Corrected tab to spaces conversion
+
+commit c17af02b4a856d8733a763e6c0685c31f3c7fb74
+Author: Nigel Hinds <nhinds@users.sourceforge.net>
+Date:   Fri Sep 19 21:51:06 2003 +0000
+
+    capture branch coverage data from GCOV.
+
+commit e2fc88f85254017bcf1fb04a3c935395a9b7a4a1
+Author: James M Kenefick Jr <parseexception@users.sourceforge.net>
+Date:   Thu Sep 4 16:56:10 2003 +0000
+
+    Initial checking of the galaxy map
+
+commit dfec606f3b30e1ac0f4114cfb98b29f91e9edb21
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Sat Jul 5 13:48:45 2003 +0000
+
+    LCOV: Fixed negative count handling
+    
+    - Negative counts are treated as zero
+    - Warning is issued when encountering negative counts
+
+commit a2ee105a07b19c52efe7a3e6e5b11a27b4b60ef8
+Author: Paul Larson <plars@users.sourceforge.net>
+Date:   Wed Jul 2 19:37:50 2003 +0000
+
+    Small fixes before the release
+
+commit 72860625dd904f84909253b20a7fc024b4e3377e
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon May 5 08:32:04 2003 +0000
+
+    Adjusted example program and README file
+    
+    ... to reflect renaming of lcov option '--reset' to '--zerocounters'.
+
+commit cbd9e315832960604d2949439326b30f4061e512
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Apr 30 15:47:51 2003 +0000
+
+    Renamed lcov option '--reset' to '--zerocounters'
+    
+    - Included '--remove' in help text of lcov
+    - Adjusted man pages to include option changes
+    - Extended info() change to geninfo and genhtml (infos are now printed
+      to STDERR)
+
+commit 8155960cb5db0359470d2a5f652bdc744e9ecfcd
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Wed Apr 16 15:43:31 2003 +0000
+
+    Modified read_gcov so that it can also parse the new gcov format which is to be introduced in gcc 3.3.
+
+commit 382440f781b12ade8f1f7962a0eb1cfc0525f2a5
+Author: Paul Larson <plars@users.sourceforge.net>
+Date:   Tue Apr 15 16:06:59 2003 +0000
+
+    Added --remove option info() now prints to stderr
+
+commit 62760fa1840326e849c7e58892ce671f510bb0af
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Mon Apr 14 09:31:51 2003 +0000
+
+    Check-in of updated LCOV version (to be released as 1.1).
+    
+    Includes fixes and modifications by Mike Kobler, Paul Larson and
+    myself.
+    
+    A quote from the CHANGS file:
+    - Added CHANGES file
+    - Added Makefile implementing the following targets:
+      * install    : install LCOV scripts and man pages
+      * uninstall  : revert previous installation
+      * dist       : create lcov.tar.gz file and lcov.rpm file
+      * clean      : clean up example directory, remove .tar and .rpm files
+    - Added man pages for all scripts
+    - Added example program to demonstrate the use of LCOV with a userspace
+      application
+    - Implemented RPM build process
+    - New directory structure:
+      * bin        : contains all executables
+      * example    : contains a userspace example for LCOV
+      * man        : contains man pages
+      * rpm        : contains files required for the RPM build process
+    - LCOV-scripts are now in bin/
+    - Removed .pl-extension from LCOV-script files
+    - Renamed readme.txt to README
+    
+    README:
+    - Adjusted mailing list address to ltp-coverage@lists.sourceforge.net
+    - Fixed incorrect parameter '--output-filename' in example LCOV call
+    - Removed tool descriptions and turned them into man pages
+    - Installation instructions now refer to RPM and tarball
+    
+    descriptions.tests:
+    - Fixed some spelling errors
+    
+    genhtml:
+    - Fixed bug which resulted in an error when trying to combine .info files
+      containing data without a test name
+    - Fixed bug which would not correctly handle data files in directories
+      with names containing some special characters ('+', etc.)
+    - Added check for empty tracefiles to prevent division-by-zeros
+    - Implemented new command line option --num-spaces / the number of spaces
+      which replace a tab in source code view is now user defined
+    - Fixed tab expansion so that in source code view, a tab doesn't produce a
+      fixed number of spaces, but as many spaces as are needed to advance to the
+      next tab position
+    - Output directory is now created if it doesn't exist
+    - Renamed "overview page" to "directory view page"
+    - HTML output pages are now titled "LCOV" instead of "GCOV"
+    
+    geninfo:
+    - Fixed bug which would not allow .info files to be generated in directories
+      with names containing some special characters
+    
+    lcov:
+    - Fixed bug which would cause lcov to fail when the tool is installed in
+      a path with a name containing some special characters
+    - Implemented new command line option '--add-tracefile' which allows the
+      combination of data from several tracefiles
+    - Implemented new command line option '--list' which lists the contents
+      of a tracefile
+    - Implemented new command line option '--extract' which allows extracting
+      data for a particular set of files from a tracefile
+    - Fixed name of gcov kernel module (new package contains gcov-prof.c)
+    - Changed name of gcov kernel directory from /proc/gcov to a global constant
+      so that it may be changed easily when required in future versions
+
+commit ec94ed71838a9780e82ea8bd67742bde2f4eeb47
+Author: Paul Larson <plars@users.sourceforge.net>
+Date:   Fri Mar 7 20:28:15 2003 +0000
+
+    Fix lcov.pl to work with the new gcov-kernel module
+    
+    ... ,documentation fixes in readme.txt
+
+commit e70d9abdb60b83de7174815371259c63fa75bf76
+Author: Robert Williamson <robbiew@users.sourceforge.net>
+Date:   Tue Feb 18 20:05:09 2003 +0000
+
+    Applied patch from Mike Kobler:
+    
+    One of my source file paths includes a "+" in the directory name.  I found
+    that genhtml.pl died when it encountered it. I was able to fix the problem
+    by modifying the string with the escape character before parsing it.
+
+commit 69ef6f1b607670589aae1ae1e6c78ef1b5d204e3
+Author: Peter Oberparleiter <oberpapr@users.sourceforge.net>
+Date:   Fri Sep 6 09:04:34 2002 +0000
+
+    Replaced reference to "cat" cvs directory
+    
+    ... and to .zip package.
+
+commit c641f6e694e2bebf9ef0a507091460026463d169
+Author: Manoj Iyer <iyermanoj@users.sourceforge.net>
+Date:   Thu Sep 5 19:14:51 2002 +0000
+
+    Coverage analysis files.
+    
+    Peter worked on this version.
diff --git a/externals/lcov/CONTRIBUTING b/externals/lcov/CONTRIBUTING
new file mode 100644
index 0000000000000000000000000000000000000000..6890789bd140c4443e89b6d3412a362860ebffda
--- /dev/null
+++ b/externals/lcov/CONTRIBUTING
@@ -0,0 +1,93 @@
+Contributing to LCOV
+====================
+
+Please read this document if you would like to help improving the LTP GCOV
+extension (LCOV). In general, all types of contributions are welcome, for
+example:
+
+ * Fixes for code or documentation
+ * Performance and compatibility improvements
+ * Functional enhancements
+
+There are some rules that these contributions must follow to be acceptable for
+inclusion:
+
+ 1. The contribution must align with the project goals of LCOV.
+ 2. The contribution must follow a particular format.
+ 3. The contribution must be signed.
+
+Once you have made sure that your contribution follows these rules, send it via
+e-mail to the LTP coverage mailing list [1].
+
+
+Signing your work
+=================
+
+All contributions to LCOV must be signed by putting the following line at the
+end of the explanation of a patch:
+
+  Signed-off-by: Your Name <your.email@example.org>
+
+By signing a patch, you certify the following:
+
+  By making a contribution to the LTP GCOV extension (LCOV) on
+  http://ltp.sourceforge.net, I certify that:
+
+  a) The contribution was created by me and I have the right to submit it
+     under the terms and conditions of the open source license
+     "GNU General Public License, version 2 or later".
+     (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
+
+  b) The contribution is made free of any other party's intellectual property
+     claims or rights.
+
+  c) I understand and agree that this project and the contribution are public
+     and that a record of the contribution (including all personal information
+     I submit with it, including my sign-off) is maintained indefinitely and
+     may be redistributed consistent with this project or the open source
+     license(s) involved.
+
+
+Project goals
+=============
+
+The goal of LCOV is to provide a set of command line tools that can be used to
+collect, process and visualize code coverage data as produced by the gcov tool
+that is part of the GNU Compiler Collection (GCC) [2].
+
+If you have an idea for a contribution but are unsure if it aligns with the
+project goals, feel free to discuss the idea on the LTP coverage mailing
+list [1].
+
+
+Contribution format
+===================
+
+To contribute a change, please create a patch using 'git format-patch'.
+Alternatively you can use the diff utility with the following command line
+options:
+
+  diff -Naurp
+
+Please base your changes on the most current version of LCOV. You can use the
+following command line to obtain this version from the lcov Git repository:
+
+ git clone https://github.com/linux-test-project/lcov.git
+
+Add a meaningful description of the contribution to the top of the patch. The
+description should follow this format:
+
+  component: short description
+
+  detailed description
+
+  Signed-off-by: Your Name <your.email@example.org>
+
+With your Signed-off-by, you certify the rules stated in section
+"Signing your work".
+
+
+-- 
+
+[1] ltp-coverage@lists.sourceforge.net
+[2] http://gcc.gnu.org
diff --git a/externals/lcov/COPYING b/externals/lcov/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..d511905c1647a1e311e8b20d5930a37a9c2531cd
--- /dev/null
+++ b/externals/lcov/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/externals/lcov/Makefile b/externals/lcov/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1207cb19add633f0b5f99f2e7c0c4ce1b95bed95
--- /dev/null
+++ b/externals/lcov/Makefile
@@ -0,0 +1,122 @@
+#
+# Makefile for LCOV
+#
+# Make targets:
+#   - install:   install LCOV tools and man pages on the system
+#   - uninstall: remove tools and man pages from the system
+#   - dist:      create files required for distribution, i.e. the lcov.tar.gz
+#                and the lcov.rpm file. Just make sure to adjust the VERSION
+#                and RELEASE variables below - both version and date strings
+#                will be updated in all necessary files.
+#   - clean:     remove all generated files
+#
+
+VERSION := $(shell bin/get_version.sh --version)
+RELEASE := $(shell bin/get_version.sh --release)
+FULL    := $(shell bin/get_version.sh --full)
+
+# Set this variable during 'make install' to specify the Perl interpreter used in
+# installed scripts, or leave empty to keep the current interpreter.
+export LCOV_PERL_PATH := /usr/bin/perl
+
+PREFIX  := /usr/local
+
+CFG_DIR := $(PREFIX)/etc
+BIN_DIR := $(PREFIX)/bin
+MAN_DIR := $(PREFIX)/share/man
+TMP_DIR := $(shell mktemp -d)
+FILES   := $(wildcard bin/*) $(wildcard man/*) README Makefile \
+	   $(wildcard rpm/*) lcovrc
+
+.PHONY: all info clean install uninstall rpms test
+
+all: info
+
+info:
+	@echo "Available make targets:"
+	@echo "  install   : install binaries and man pages in DESTDIR (default /)"
+	@echo "  uninstall : delete binaries and man pages from DESTDIR (default /)"
+	@echo "  dist      : create packages (RPM, tarball) ready for distribution"
+	@echo "  test      : perform self-tests"
+
+clean:
+	rm -f lcov-*.tar.gz
+	rm -f lcov-*.rpm
+	make -C example clean
+	make -C test -s clean
+
+install:
+	bin/install.sh bin/lcov $(DESTDIR)$(BIN_DIR)/lcov -m 755
+	bin/install.sh bin/genhtml $(DESTDIR)$(BIN_DIR)/genhtml -m 755
+	bin/install.sh bin/geninfo $(DESTDIR)$(BIN_DIR)/geninfo -m 755
+	bin/install.sh bin/genpng $(DESTDIR)$(BIN_DIR)/genpng -m 755
+	bin/install.sh bin/gendesc $(DESTDIR)$(BIN_DIR)/gendesc -m 755
+	bin/install.sh man/lcov.1 $(DESTDIR)$(MAN_DIR)/man1/lcov.1 -m 644
+	bin/install.sh man/genhtml.1 $(DESTDIR)$(MAN_DIR)/man1/genhtml.1 -m 644
+	bin/install.sh man/geninfo.1 $(DESTDIR)$(MAN_DIR)/man1/geninfo.1 -m 644
+	bin/install.sh man/genpng.1 $(DESTDIR)$(MAN_DIR)/man1/genpng.1 -m 644
+	bin/install.sh man/gendesc.1 $(DESTDIR)$(MAN_DIR)/man1/gendesc.1 -m 644
+	bin/install.sh man/lcovrc.5 $(DESTDIR)$(MAN_DIR)/man5/lcovrc.5 -m 644
+	bin/install.sh lcovrc $(DESTDIR)$(CFG_DIR)/lcovrc -m 644
+	bin/updateversion.pl $(DESTDIR)$(BIN_DIR)/lcov $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(BIN_DIR)/genhtml $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(BIN_DIR)/geninfo $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(BIN_DIR)/genpng $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(BIN_DIR)/gendesc $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(MAN_DIR)/man1/lcov.1 $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(MAN_DIR)/man1/genhtml.1 $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(MAN_DIR)/man1/geninfo.1 $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(MAN_DIR)/man1/genpng.1 $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(MAN_DIR)/man1/gendesc.1 $(VERSION) $(RELEASE) $(FULL)
+	bin/updateversion.pl $(DESTDIR)$(MAN_DIR)/man5/lcovrc.5 $(VERSION) $(RELEASE) $(FULL)
+
+uninstall:
+	bin/install.sh --uninstall bin/lcov $(DESTDIR)$(BIN_DIR)/lcov
+	bin/install.sh --uninstall bin/genhtml $(DESTDIR)$(BIN_DIR)/genhtml
+	bin/install.sh --uninstall bin/geninfo $(DESTDIR)$(BIN_DIR)/geninfo
+	bin/install.sh --uninstall bin/genpng $(DESTDIR)$(BIN_DIR)/genpng
+	bin/install.sh --uninstall bin/gendesc $(DESTDIR)$(BIN_DIR)/gendesc
+	bin/install.sh --uninstall man/lcov.1 $(DESTDIR)$(MAN_DIR)/man1/lcov.1
+	bin/install.sh --uninstall man/genhtml.1 $(DESTDIR)$(MAN_DIR)/man1/genhtml.1
+	bin/install.sh --uninstall man/geninfo.1 $(DESTDIR)$(MAN_DIR)/man1/geninfo.1
+	bin/install.sh --uninstall man/genpng.1 $(DESTDIR)$(MAN_DIR)/man1/genpng.1
+	bin/install.sh --uninstall man/gendesc.1 $(DESTDIR)$(MAN_DIR)/man1/gendesc.1
+	bin/install.sh --uninstall man/lcovrc.5 $(DESTDIR)$(MAN_DIR)/man5/lcovrc.5
+	bin/install.sh --uninstall lcovrc $(DESTDIR)$(CFG_DIR)/lcovrc
+
+dist: lcov-$(VERSION).tar.gz lcov-$(VERSION)-$(RELEASE).noarch.rpm \
+      lcov-$(VERSION)-$(RELEASE).src.rpm
+
+lcov-$(VERSION).tar.gz: $(FILES)
+	mkdir $(TMP_DIR)/lcov-$(VERSION)
+	cp -r * $(TMP_DIR)/lcov-$(VERSION)
+	bin/copy_dates.sh . $(TMP_DIR)/lcov-$(VERSION)
+	make -C $(TMP_DIR)/lcov-$(VERSION) clean
+	bin/updateversion.pl $(TMP_DIR)/lcov-$(VERSION) $(VERSION) $(RELEASE) $(FULL)
+	bin/get_changes.sh > $(TMP_DIR)/lcov-$(VERSION)/CHANGES
+	cd $(TMP_DIR) ; \
+	tar cfz $(TMP_DIR)/lcov-$(VERSION).tar.gz lcov-$(VERSION)
+	mv $(TMP_DIR)/lcov-$(VERSION).tar.gz .
+	rm -rf $(TMP_DIR)
+
+lcov-$(VERSION)-$(RELEASE).noarch.rpm: rpms
+lcov-$(VERSION)-$(RELEASE).src.rpm: rpms
+
+rpms: lcov-$(VERSION).tar.gz
+	mkdir $(TMP_DIR)
+	mkdir $(TMP_DIR)/BUILD
+	mkdir $(TMP_DIR)/RPMS
+	mkdir $(TMP_DIR)/SOURCES
+	mkdir $(TMP_DIR)/SRPMS
+	cp lcov-$(VERSION).tar.gz $(TMP_DIR)/SOURCES
+	cd $(TMP_DIR)/BUILD ; \
+	tar xfz $(TMP_DIR)/SOURCES/lcov-$(VERSION).tar.gz \
+		lcov-$(VERSION)/rpm/lcov.spec
+	rpmbuild --define '_topdir $(TMP_DIR)' \
+		 -ba $(TMP_DIR)/BUILD/lcov-$(VERSION)/rpm/lcov.spec
+	mv $(TMP_DIR)/RPMS/noarch/lcov-$(VERSION)-$(RELEASE).noarch.rpm .
+	mv $(TMP_DIR)/SRPMS/lcov-$(VERSION)-$(RELEASE).src.rpm .
+	rm -rf $(TMP_DIR)
+
+test:
+	@make -C test -s all
diff --git a/externals/lcov/README b/externals/lcov/README
new file mode 100644
index 0000000000000000000000000000000000000000..ad53c3cbcbf06c6cd326b2bac49cd973ebf6bb8b
--- /dev/null
+++ b/externals/lcov/README
@@ -0,0 +1,135 @@
+-------------------------------------------------
+- README file for the LTP GCOV extension (LCOV) -
+- Last changes: 2019-02-28                      -
+-------------------------------------------------
+
+Description
+-----------
+  LCOV is an extension of GCOV, a GNU tool which provides information about
+  what parts of a program are actually executed (i.e. "covered") while running
+  a particular test case. The extension consists of a set of Perl scripts
+  which build on the textual GCOV output to implement the following enhanced
+  functionality:
+
+    * HTML based output: coverage rates are additionally indicated using bar
+      graphs and specific colors.
+
+    * Support for large projects: overview pages allow quick browsing of
+      coverage data by providing three levels of detail: directory view,
+      file view and source code view.
+
+  LCOV was initially designed to support Linux kernel coverage measurements,
+  but works as well for coverage measurements on standard user space
+  applications.
+
+
+Further README contents
+-----------------------
+  1. Included files
+  2. Installing LCOV
+  3. An example of how to access kernel coverage data
+  4. An example of how to access coverage data for a user space program
+  5. Questions and Comments
+
+
+
+1. Important files
+------------------
+  README             - This README file
+  CHANGES            - List of changes between releases
+  bin/lcov           - Tool for capturing LCOV coverage data
+  bin/genhtml        - Tool for creating HTML output from LCOV data
+  bin/gendesc        - Tool for creating description files as used by genhtml
+  bin/geninfo        - Internal tool (creates LCOV data files)
+  bin/genpng         - Internal tool (creates png overviews of source files)
+  bin/install.sh     - Internal tool (takes care of un-/installing)
+  man                - Directory containing man pages for included tools
+  example            - Directory containing an example to demonstrate LCOV
+  lcovrc             - LCOV configuration file
+  Makefile           - Makefile providing 'install' and 'uninstall' targets
+
+
+2. Installing LCOV
+------------------
+The LCOV package is available as either RPM or tarball from:
+     
+  http://ltp.sourceforge.net/coverage/lcov.php
+
+To install the tarball, unpack it to a directory and run:
+
+  make install
+
+Use Git for the most recent (but possibly unstable) version:
+
+  git clone https://github.com/linux-test-project/lcov.git
+
+Change to the resulting lcov directory and type:
+
+  make install
+
+
+3. An example of how to access kernel coverage data
+---------------------------------------------------
+Requirements: get and install the gcov-kernel package from
+
+  http://sourceforge.net/projects/ltp
+
+Copy the resulting gcov kernel module file to either the system wide modules
+directory or the same directory as the Perl scripts. As root, do the following:
+
+  a) Resetting counters
+
+     lcov --zerocounters
+
+  b) Capturing the current coverage state to a file
+
+     lcov --capture --output-file kernel.info
+
+  c) Getting HTML output
+
+     genhtml kernel.info
+
+Point the web browser of your choice to the resulting index.html file.
+
+
+4. An example of how to access coverage data for a user space program
+---------------------------------------------------------------------
+Requirements: compile the program in question using GCC with the options
+-fprofile-arcs and -ftest-coverage. During linking, make sure to specify
+-lgcov or -coverage.
+
+Assuming the compile directory is called "appdir", do the following:
+
+  a) Resetting counters
+
+     lcov --directory appdir --zerocounters
+
+  b) Capturing the current coverage state to a file
+
+     lcov --directory appdir --capture --output-file app.info
+
+     Note that this step only works after the application has
+     been started and stopped at least once. Otherwise lcov will
+     abort with an error mentioning that there are no data/.gcda files.
+
+  c) Getting HTML output
+
+     genhtml app.info
+
+Point the web browser of your choice to the resulting index.html file.
+
+Please note that independently of where the application is installed or
+from which directory it is run, the --directory statement needs to
+point to the directory in which the application was compiled.
+
+For further information on the gcc profiling mechanism, please also
+consult the gcov man page.
+
+
+5. Questions and comments
+-------------------------
+See the included man pages for more information on how to use the LCOV tools.
+
+Please email further questions or comments regarding this tool to the
+LTP Mailing list at ltp-coverage@lists.sourceforge.net  
+
diff --git a/externals/lcov/bin/copy_dates.sh b/externals/lcov/bin/copy_dates.sh
new file mode 100755
index 0000000000000000000000000000000000000000..aef5f5ed36cfce1d36186425b2260c5fee94a51a
--- /dev/null
+++ b/externals/lcov/bin/copy_dates.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+# Usage: copy_dates.sh SOURCE TARGET
+#
+# For each file found in SOURCE, set the modification time of the copy of that
+# file in TARGET to either the time of the latest Git commit (if SOURCE contains
+# a Git repository and the file was not modified after the last commit), or the
+# modification time of the original file.
+
+SOURCE="$1"
+TARGET="$2"
+
+if [ -z "$SOURCE" -o -z "$TARGET" ] ; then
+	echo "Usage: $0 SOURCE TARGET" >&2
+	exit 1
+fi
+
+[ -d "$SOURCE/.git" ] ; NOGIT=$?
+
+echo "Copying modification/commit times from $SOURCE to $TARGET"
+
+cd "$SOURCE" || exit 1
+find * -type f | while read FILENAME ; do
+	[ ! -e "$TARGET/$FILENAME" ] && continue
+
+	# Copy modification time
+	touch -m "$TARGET/$FILENAME" -r "$FILENAME"
+
+	[ $NOGIT -eq 1 ] && continue				# No Git
+	git diff --quiet -- "$FILENAME" || continue		# Modified
+	git diff --quiet --cached -- "$FILENAME" || continue	# Modified
+
+	# Apply modification time from Git commit time
+	TIME=$(git log --pretty=format:%cd -n 1 --date=iso -- "$FILENAME")
+	[ -n "$TIME" ] && touch -m "$TARGET/$FILENAME" --date "$TIME"
+done
diff --git a/externals/lcov/bin/gendesc b/externals/lcov/bin/gendesc
new file mode 100755
index 0000000000000000000000000000000000000000..334ee7892372935d48dc349ce2fb3cc373af3080
--- /dev/null
+++ b/externals/lcov/bin/gendesc
@@ -0,0 +1,226 @@
+#!/usr/bin/env perl
+#
+#   Copyright (c) International Business Machines  Corp., 2002
+#
+#   This program is free software;  you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY;  without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.                 
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program;  if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# gendesc
+#
+#   This script creates a description file as understood by genhtml.
+#   Input file format:
+#
+#   For each test case:
+#     <test name><optional whitespace>
+#     <at least one whitespace character (blank/tab)><test description>
+#   
+#   Actual description may consist of several lines. By default, output is
+#   written to stdout. Test names consist of alphanumeric characters
+#   including _ and -.
+#
+#
+# History:
+#   2002-09-02: created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+#
+
+use strict;
+use warnings;
+use File::Basename; 
+use Getopt::Long;
+use Cwd qw/abs_path/;
+
+
+# Constants
+our $tool_dir		= abs_path(dirname($0));
+our $lcov_version	= "LCOV version 1.14";
+our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $tool_name		= basename($0);
+
+
+# Prototypes
+sub print_usage(*);
+sub gen_desc();
+sub warn_handler($);
+sub die_handler($);
+
+
+# Global variables
+our $help;
+our $version;
+our $output_filename;
+our $input_filename;
+
+
+#
+# Code entry point
+#
+
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+
+# Parse command line options
+if (!GetOptions("output-filename=s" => \$output_filename,
+		"version" =>\$version,
+		"help|?" => \$help
+		))
+{
+	print(STDERR "Use $tool_name --help to get usage information\n");
+	exit(1);
+}
+
+$input_filename = $ARGV[0];
+
+# Check for help option
+if ($help)
+{
+	print_usage(*STDOUT);
+	exit(0);
+}
+
+# Check for version option
+if ($version)
+{
+	print("$tool_name: $lcov_version\n");
+	exit(0);
+}
+
+
+# Check for input filename
+if (!$input_filename)
+{
+	die("No input filename specified\n".
+	    "Use $tool_name --help to get usage information\n");
+}
+
+# Do something
+gen_desc();
+
+
+#
+# print_usage(handle)
+#
+# Write out command line usage information to given filehandle.
+#
+
+sub print_usage(*)
+{
+	local *HANDLE = $_[0];
+
+	print(HANDLE <<END_OF_USAGE)
+Usage: $tool_name [OPTIONS] INPUTFILE
+
+Convert a test case description file into a format as understood by genhtml.
+
+  -h, --help                        Print this help, then exit
+  -v, --version                     Print version number, then exit
+  -o, --output-filename FILENAME    Write description to FILENAME
+
+For more information see: $lcov_url
+END_OF_USAGE
+	;
+}
+
+
+#
+# gen_desc()
+#
+# Read text file INPUT_FILENAME and convert the contained description to a
+# format as understood by genhtml, i.e.
+#
+#    TN:<test name>
+#    TD:<test description>
+#
+# If defined, write output to OUTPUT_FILENAME, otherwise to stdout.
+#
+# Die on error.
+#
+
+sub gen_desc()
+{
+	local *INPUT_HANDLE;
+	local *OUTPUT_HANDLE;
+	my $empty_line = "ignore";
+
+	open(INPUT_HANDLE, "<", $input_filename)
+		or die("ERROR: cannot open $input_filename!\n");
+
+	# Open output file for writing
+	if ($output_filename)
+	{
+		open(OUTPUT_HANDLE, ">", $output_filename)
+			or die("ERROR: cannot create $output_filename!\n");
+	}
+	else
+	{
+		*OUTPUT_HANDLE = *STDOUT;
+	}
+
+	# Process all lines in input file
+	while (<INPUT_HANDLE>)
+	{
+		chomp($_);
+
+		if (/^(\w[\w-]*)(\s*)$/)
+		{
+			# Matched test name
+			# Name starts with alphanum or _, continues with
+			# alphanum, _ or -
+			print(OUTPUT_HANDLE "TN: $1\n");
+			$empty_line = "ignore";
+		}
+		elsif (/^(\s+)(\S.*?)\s*$/)
+		{
+			# Matched test description
+			if ($empty_line eq "insert")
+			{
+				# Write preserved empty line
+				print(OUTPUT_HANDLE "TD: \n");
+			}
+			print(OUTPUT_HANDLE "TD: $2\n");
+			$empty_line = "observe";
+		}
+		elsif (/^\s*$/)
+		{
+			# Matched empty line to preserve paragraph separation
+			# inside description text
+			if ($empty_line eq "observe")
+			{
+				$empty_line = "insert";
+			}
+		}
+	}
+
+	# Close output file if defined
+	if ($output_filename)
+	{
+		close(OUTPUT_HANDLE);
+	}
+
+	close(INPUT_HANDLE);
+}
+
+sub warn_handler($)
+{
+	my ($msg) = @_;
+
+	warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+	my ($msg) = @_;
+
+	die("$tool_name: $msg");
+}
diff --git a/externals/lcov/bin/genhtml b/externals/lcov/bin/genhtml
new file mode 100755
index 0000000000000000000000000000000000000000..2352300c11403acdc39f4b27582d68f6387ac685
--- /dev/null
+++ b/externals/lcov/bin/genhtml
@@ -0,0 +1,5974 @@
+#!/usr/bin/env perl
+#
+#   Copyright (c) International Business Machines  Corp., 2002,2012
+#
+#   This program is free software;  you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY;  without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details. 
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program;  if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# genhtml
+#
+#   This script generates HTML output from .info files as created by the
+#   geninfo script. Call it with --help and refer to the genhtml man page
+#   to get information on usage and available options.
+#
+#
+# History:
+#   2002-08-23 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+#                         IBM Lab Boeblingen
+#        based on code by Manoj Iyer <manjo@mail.utexas.edu> and
+#                         Megan Bock <mbock@us.ibm.com>
+#                         IBM Austin
+#   2002-08-27 / Peter Oberparleiter: implemented frame view
+#   2002-08-29 / Peter Oberparleiter: implemented test description filtering
+#                so that by default only descriptions for test cases which
+#                actually hit some source lines are kept
+#   2002-09-05 / Peter Oberparleiter: implemented --no-sourceview
+#   2002-09-05 / Mike Kobler: One of my source file paths includes a "+" in
+#                the directory name.  I found that genhtml.pl died when it
+#                encountered it. I was able to fix the problem by modifying
+#                the string with the escape character before parsing it.
+#   2002-10-26 / Peter Oberparleiter: implemented --num-spaces
+#   2003-04-07 / Peter Oberparleiter: fixed bug which resulted in an error
+#                when trying to combine .info files containing data without
+#                a test name
+#   2003-04-10 / Peter Oberparleiter: extended fix by Mike to also cover
+#                other special characters
+#   2003-04-30 / Peter Oberparleiter: made info write to STDERR, not STDOUT
+#   2003-07-10 / Peter Oberparleiter: added line checksum support
+#   2004-08-09 / Peter Oberparleiter: added configuration file support
+#   2005-03-04 / Cal Pierog: added legend to HTML output, fixed coloring of
+#                "good coverage" background
+#   2006-03-18 / Marcus Boerger: added --custom-intro, --custom-outro and
+#                overwrite --no-prefix if --prefix is present
+#   2006-03-20 / Peter Oberparleiter: changes to custom_* function (rename
+#                to html_prolog/_epilog, minor modifications to implementation),
+#                changed prefix/noprefix handling to be consistent with current
+#                logic
+#   2006-03-20 / Peter Oberparleiter: added --html-extension option
+#   2008-07-14 / Tom Zoerner: added --function-coverage command line option;
+#                added function table to source file page
+#   2008-08-13 / Peter Oberparleiter: modified function coverage
+#                implementation (now enabled per default),
+#                introduced sorting option (enabled per default)
+#
+
+use strict;
+use warnings;
+use File::Basename;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+use Digest::MD5 qw(md5_base64);
+use Cwd qw/abs_path cwd/;
+
+
+# Global constants
+our $title		= "LCOV - code coverage report";
+our $tool_dir		= abs_path(dirname($0));
+our $lcov_version	= "LCOV version 1.14";
+our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $tool_name		= basename($0);
+
+# Specify coverage rate default precision
+our $default_precision = 1;
+
+# Specify coverage rate limits (in %) for classifying file entries
+# HI:   $hi_limit <= rate <= 100          graph color: green
+# MED: $med_limit <= rate <  $hi_limit    graph color: orange
+# LO:          0  <= rate <  $med_limit   graph color: red
+
+# For line coverage/all coverage types if not specified
+our $hi_limit = 90;
+our $med_limit = 75;
+
+# For function coverage
+our $fn_hi_limit;
+our $fn_med_limit;
+
+# For branch coverage
+our $br_hi_limit;
+our $br_med_limit;
+
+# Width of overview image
+our $overview_width = 80;
+
+# Resolution of overview navigation: this number specifies the maximum
+# difference in lines between the position a user selected from the overview
+# and the position the source code window is scrolled to.
+our $nav_resolution = 4;
+
+# Clicking a line in the overview image should show the source code view at
+# a position a bit further up so that the requested line is not the first
+# line in the window. This number specifies that offset in lines.
+our $nav_offset = 10;
+
+# Clicking on a function name should show the source code at a position a
+# few lines before the first line of code of that function. This number
+# specifies that offset in lines.
+our $func_offset = 2;
+
+our $overview_title = "top level";
+
+# Width for line coverage information in the source code view
+our $line_field_width = 12;
+
+# Width for branch coverage information in the source code view
+our $br_field_width = 16;
+
+# Internal Constants
+
+# Header types
+our $HDR_DIR		= 0;
+our $HDR_FILE		= 1;
+our $HDR_SOURCE		= 2;
+our $HDR_TESTDESC	= 3;
+our $HDR_FUNC		= 4;
+
+# Sort types
+our $SORT_FILE		= 0;
+our $SORT_LINE		= 1;
+our $SORT_FUNC		= 2;
+our $SORT_BRANCH	= 3;
+
+# Fileview heading types
+our $HEAD_NO_DETAIL	= 1;
+our $HEAD_DETAIL_HIDDEN	= 2;
+our $HEAD_DETAIL_SHOWN	= 3;
+
+# Additional offsets used when converting branch coverage data to HTML
+our $BR_LEN	= 3;
+our $BR_OPEN	= 4;
+our $BR_CLOSE	= 5;
+
+# Branch data combination types
+our $BR_SUB = 0;
+our $BR_ADD = 1;
+
+# Error classes which users may specify to ignore during processing
+our $ERROR_SOURCE	= 0;
+our %ERROR_ID = (
+	"source" => $ERROR_SOURCE,
+);
+
+# Data related prototypes
+sub print_usage(*);
+sub gen_html();
+sub html_create($$);
+sub process_dir($);
+sub process_file($$$);
+sub info(@);
+sub read_info_file($);
+sub get_info_entry($);
+sub set_info_entry($$$$$$$$$;$$$$$$);
+sub get_prefix($@);
+sub shorten_prefix($);
+sub get_dir_list(@);
+sub get_relative_base_path($);
+sub read_testfile($);
+sub get_date_string();
+sub create_sub_dir($);
+sub subtract_counts($$);
+sub add_counts($$);
+sub apply_baseline($$);
+sub remove_unused_descriptions();
+sub get_found_and_hit($);
+sub get_affecting_tests($$$);
+sub combine_info_files($$);
+sub merge_checksums($$$);
+sub combine_info_entries($$$);
+sub apply_prefix($@);
+sub system_no_output($@);
+sub read_config($);
+sub apply_config($);
+sub get_html_prolog($);
+sub get_html_epilog($);
+sub write_dir_page($$$$$$$$$$$$$$$$$);
+sub classify_rate($$$$);
+sub combine_brcount($$$;$);
+sub get_br_found_and_hit($);
+sub warn_handler($);
+sub die_handler($);
+sub parse_ignore_errors(@);
+sub parse_dir_prefix(@);
+sub rate($$;$$$);
+
+
+# HTML related prototypes
+sub escape_html($);
+sub get_bar_graph_code($$$);
+
+sub write_png_files();
+sub write_htaccess_file();
+sub write_css_file();
+sub write_description_file($$$$$$$);
+sub write_function_table(*$$$$$$$$$$);
+
+sub write_html(*$);
+sub write_html_prolog(*$$);
+sub write_html_epilog(*$;$);
+
+sub write_header(*$$$$$$$$$$);
+sub write_header_prolog(*$);
+sub write_header_line(*@);
+sub write_header_epilog(*$);
+
+sub write_file_table(*$$$$$$$);
+sub write_file_table_prolog(*$@);
+sub write_file_table_entry(*$$$@);
+sub write_file_table_detail_entry(*$@);
+sub write_file_table_epilog(*);
+
+sub write_test_table_prolog(*$);
+sub write_test_table_entry(*$$);
+sub write_test_table_epilog(*);
+
+sub write_source($$$$$$$);
+sub write_source_prolog(*);
+sub write_source_line(*$$$$$);
+sub write_source_epilog(*);
+
+sub write_frameset(*$$$);
+sub write_overview_line(*$$$);
+sub write_overview(*$$$$);
+
+# External prototype (defined in genpng)
+sub gen_png($$$@);
+
+
+# Global variables & initialization
+our %info_data;		# Hash containing all data from .info file
+our @opt_dir_prefix;	# Array of prefixes to remove from all sub directories
+our @dir_prefix;
+our %test_description;	# Hash containing test descriptions if available
+our $date = get_date_string();
+
+our @info_filenames;	# List of .info files to use as data source
+our $test_title;	# Title for output as written to each page header
+our $output_directory;	# Name of directory in which to store output
+our $base_filename;	# Optional name of file containing baseline data
+our $desc_filename;	# Name of file containing test descriptions
+our $css_filename;	# Optional name of external stylesheet file to use
+our $quiet;		# If set, suppress information messages
+our $help;		# Help option flag
+our $version;		# Version option flag
+our $show_details;	# If set, generate detailed directory view
+our $no_prefix;		# If set, do not remove filename prefix
+our $func_coverage;	# If set, generate function coverage statistics
+our $no_func_coverage;	# Disable func_coverage
+our $br_coverage;	# If set, generate branch coverage statistics
+our $no_br_coverage;	# Disable br_coverage
+our $sort = 1;		# If set, provide directory listings with sorted entries
+our $no_sort;		# Disable sort
+our $frames;		# If set, use frames for source code view
+our $keep_descriptions;	# If set, do not remove unused test case descriptions
+our $no_sourceview;	# If set, do not create a source code view for each file
+our $highlight;		# If set, highlight lines covered by converted data only
+our $legend;		# If set, include legend in output
+our $tab_size = 8;	# Number of spaces to use in place of tab
+our $config;		# Configuration file contents
+our $html_prolog_file;	# Custom HTML prolog file (up to and including <body>)
+our $html_epilog_file;	# Custom HTML epilog file (from </body> onwards)
+our $html_prolog;	# Actual HTML prolog
+our $html_epilog;	# Actual HTML epilog
+our $html_ext = "html";	# Extension for generated HTML files
+our $html_gzip = 0;	# Compress with gzip
+our $demangle_cpp = 0;	# Demangle C++ function names
+our @opt_ignore_errors;	# Ignore certain error classes during processing
+our @ignore;
+our $opt_config_file;	# User-specified configuration file location
+our %opt_rc;
+our $opt_missed;	# List/sort lines by missed counts
+our $charset = "UTF-8";	# Default charset for HTML pages
+our @fileview_sortlist;
+our @fileview_sortname = ("", "-sort-l", "-sort-f", "-sort-b");
+our @funcview_sortlist;
+our @rate_name = ("Lo", "Med", "Hi");
+our @rate_png = ("ruby.png", "amber.png", "emerald.png");
+our $lcov_func_coverage = 1;
+our $lcov_branch_coverage = 0;
+our $rc_desc_html = 0;	# lcovrc: genhtml_desc_html
+
+our $cwd = cwd();	# Current working directory
+
+
+#
+# Code entry point
+#
+
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+	   "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
+
+{
+	# Remove spaces around rc options
+	my %new_opt_rc;
+
+	while (my ($key, $value) = each(%opt_rc)) {
+		$key =~ s/^\s+|\s+$//g;
+		$value =~ s/^\s+|\s+$//g;
+
+		$new_opt_rc{$key} = $value;
+	}
+	%opt_rc = %new_opt_rc;
+}
+
+# Read configuration file if available
+if (defined($opt_config_file)) {
+	$config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
+{
+	$config = read_config($ENV{"HOME"}."/.lcovrc");
+}
+elsif (-r "/etc/lcovrc")
+{
+	$config = read_config("/etc/lcovrc");
+} elsif (-r "/usr/local/etc/lcovrc")
+{
+	$config = read_config("/usr/local/etc/lcovrc");
+}
+
+if ($config || %opt_rc)
+{
+	# Copy configuration file and --rc values to variables
+	apply_config({
+		"genhtml_css_file"		=> \$css_filename,
+		"genhtml_hi_limit"		=> \$hi_limit,
+		"genhtml_med_limit"		=> \$med_limit,
+		"genhtml_line_field_width"	=> \$line_field_width,
+		"genhtml_overview_width"	=> \$overview_width,
+		"genhtml_nav_resolution"	=> \$nav_resolution,
+		"genhtml_nav_offset"		=> \$nav_offset,
+		"genhtml_keep_descriptions"	=> \$keep_descriptions,
+		"genhtml_no_prefix"		=> \$no_prefix,
+		"genhtml_no_source"		=> \$no_sourceview,
+		"genhtml_num_spaces"		=> \$tab_size,
+		"genhtml_highlight"		=> \$highlight,
+		"genhtml_legend"		=> \$legend,
+		"genhtml_html_prolog"		=> \$html_prolog_file,
+		"genhtml_html_epilog"		=> \$html_epilog_file,
+		"genhtml_html_extension"	=> \$html_ext,
+		"genhtml_html_gzip"		=> \$html_gzip,
+		"genhtml_precision"		=> \$default_precision,
+		"genhtml_function_hi_limit"	=> \$fn_hi_limit,
+		"genhtml_function_med_limit"	=> \$fn_med_limit,
+		"genhtml_function_coverage"	=> \$func_coverage,
+		"genhtml_branch_hi_limit"	=> \$br_hi_limit,
+		"genhtml_branch_med_limit"	=> \$br_med_limit,
+		"genhtml_branch_coverage"	=> \$br_coverage,
+		"genhtml_branch_field_width"	=> \$br_field_width,
+		"genhtml_sort"			=> \$sort,
+		"genhtml_charset"		=> \$charset,
+		"genhtml_desc_html"		=> \$rc_desc_html,
+		"genhtml_demangle_cpp"		=> \$demangle_cpp,
+		"genhtml_missed"		=> \$opt_missed,
+		"lcov_function_coverage"	=> \$lcov_func_coverage,
+		"lcov_branch_coverage"		=> \$lcov_branch_coverage,
+		});
+}
+
+# Copy related values if not specified
+$fn_hi_limit	= $hi_limit if (!defined($fn_hi_limit));
+$fn_med_limit	= $med_limit if (!defined($fn_med_limit));
+$br_hi_limit	= $hi_limit if (!defined($br_hi_limit));
+$br_med_limit	= $med_limit if (!defined($br_med_limit));
+$func_coverage	= $lcov_func_coverage if (!defined($func_coverage));
+$br_coverage	= $lcov_branch_coverage if (!defined($br_coverage));
+
+# Parse command line options
+if (!GetOptions("output-directory|o=s"	=> \$output_directory,
+		"title|t=s"		=> \$test_title,
+		"description-file|d=s"	=> \$desc_filename,
+		"keep-descriptions|k"	=> \$keep_descriptions,
+		"css-file|c=s"		=> \$css_filename,
+		"baseline-file|b=s"	=> \$base_filename,
+		"prefix|p=s"		=> \@opt_dir_prefix,
+		"num-spaces=i"		=> \$tab_size,
+		"no-prefix"		=> \$no_prefix,
+		"no-sourceview"		=> \$no_sourceview,
+		"show-details|s"	=> \$show_details,
+		"frames|f"		=> \$frames,
+		"highlight"		=> \$highlight,
+		"legend"		=> \$legend,
+		"quiet|q"		=> \$quiet,
+		"help|h|?"		=> \$help,
+		"version|v"		=> \$version,
+		"html-prolog=s"		=> \$html_prolog_file,
+		"html-epilog=s"		=> \$html_epilog_file,
+		"html-extension=s"	=> \$html_ext,
+		"html-gzip"		=> \$html_gzip,
+		"function-coverage"	=> \$func_coverage,
+		"no-function-coverage"	=> \$no_func_coverage,
+		"branch-coverage"	=> \$br_coverage,
+		"no-branch-coverage"	=> \$no_br_coverage,
+		"sort"			=> \$sort,
+		"no-sort"		=> \$no_sort,
+		"demangle-cpp"		=> \$demangle_cpp,
+		"ignore-errors=s"	=> \@opt_ignore_errors,
+		"config-file=s"		=> \$opt_config_file,
+		"rc=s%"			=> \%opt_rc,
+		"precision=i"		=> \$default_precision,
+		"missed"		=> \$opt_missed,
+		))
+{
+	print(STDERR "Use $tool_name --help to get usage information\n");
+	exit(1);
+} else {
+	# Merge options
+	if ($no_func_coverage) {
+		$func_coverage = 0;
+	}
+	if ($no_br_coverage) {
+		$br_coverage = 0;
+	}
+
+	# Merge sort options
+	if ($no_sort) {
+		$sort = 0;
+	}
+}
+
+@info_filenames = @ARGV;
+
+# Check for help option
+if ($help)
+{
+	print_usage(*STDOUT);
+	exit(0);
+}
+
+# Check for version option
+if ($version)
+{
+	print("$tool_name: $lcov_version\n");
+	exit(0);
+}
+
+# Determine which errors the user wants us to ignore
+parse_ignore_errors(@opt_ignore_errors);
+
+# Split the list of prefixes if needed
+parse_dir_prefix(@opt_dir_prefix);
+
+# Check for info filename
+if (!@info_filenames)
+{
+	die("No filename specified\n".
+	    "Use $tool_name --help to get usage information\n");
+}
+
+# Generate a title if none is specified
+if (!$test_title)
+{
+	if (scalar(@info_filenames) == 1)
+	{
+		# Only one filename specified, use it as title
+		$test_title = basename($info_filenames[0]);
+	}
+	else
+	{
+		# More than one filename specified, used default title
+		$test_title = "unnamed";
+	}
+}
+
+# Make sure css_filename is an absolute path (in case we're changing
+# directories)
+if ($css_filename)
+{
+	if (!($css_filename =~ /^\/(.*)$/))
+	{
+		$css_filename = $cwd."/".$css_filename;
+	}
+}
+
+# Make sure tab_size is within valid range
+if ($tab_size < 1)
+{
+	print(STDERR "ERROR: invalid number of spaces specified: ".
+		     "$tab_size!\n");
+	exit(1);
+}
+
+# Get HTML prolog and epilog
+$html_prolog = get_html_prolog($html_prolog_file);
+$html_epilog = get_html_epilog($html_epilog_file);
+
+# Issue a warning if --no-sourceview is enabled together with --frames
+if ($no_sourceview && defined($frames))
+{
+	warn("WARNING: option --frames disabled because --no-sourceview ".
+	     "was specified!\n");
+	$frames = undef;
+}
+
+# Issue a warning if --no-prefix is enabled together with --prefix
+if ($no_prefix && @dir_prefix)
+{
+	warn("WARNING: option --prefix disabled because --no-prefix was ".
+	     "specified!\n");
+	@dir_prefix = undef;
+}
+
+@fileview_sortlist = ($SORT_FILE);
+@funcview_sortlist = ($SORT_FILE);
+
+if ($sort) {
+	push(@fileview_sortlist, $SORT_LINE);
+	push(@fileview_sortlist, $SORT_FUNC) if ($func_coverage);
+	push(@fileview_sortlist, $SORT_BRANCH) if ($br_coverage);
+	push(@funcview_sortlist, $SORT_LINE);
+}
+
+if ($frames)
+{
+	# Include genpng code needed for overview image generation
+	do("$tool_dir/genpng");
+}
+
+# Ensure that the c++filt tool is available when using --demangle-cpp
+if ($demangle_cpp)
+{
+	if (system_no_output(3, "c++filt", "--version")) {
+		die("ERROR: could not find c++filt tool needed for ".
+		    "--demangle-cpp\n");
+	}
+}
+
+# Make sure precision is within valid range
+if ($default_precision < 1 || $default_precision > 4)
+{
+	die("ERROR: specified precision is out of range (1 to 4)\n");
+}
+
+
+# Make sure output_directory exists, create it if necessary
+if ($output_directory)
+{
+	stat($output_directory);
+
+	if (! -e _)
+	{
+		create_sub_dir($output_directory);
+	}
+}
+
+# Do something
+gen_html();
+
+exit(0);
+
+
+
+#
+# print_usage(handle)
+#
+# Print usage information.
+#
+
+sub print_usage(*)
+{
+	local *HANDLE = $_[0];
+
+	print(HANDLE <<END_OF_USAGE);
+Usage: $tool_name [OPTIONS] INFOFILE(S)
+
+Create HTML output for coverage data found in INFOFILE. Note that INFOFILE
+may also be a list of filenames.
+
+Misc:
+  -h, --help                        Print this help, then exit
+  -v, --version                     Print version number, then exit
+  -q, --quiet                       Do not print progress messages
+      --config-file FILENAME        Specify configuration file location
+      --rc SETTING=VALUE            Override configuration file setting
+      --ignore-errors ERRORS        Continue after ERRORS (source)
+
+Operation:
+  -o, --output-directory OUTDIR     Write HTML output to OUTDIR
+  -s, --show-details                Generate detailed directory view
+  -d, --description-file DESCFILE   Read test case descriptions from DESCFILE
+  -k, --keep-descriptions           Do not remove unused test descriptions
+  -b, --baseline-file BASEFILE      Use BASEFILE as baseline file
+  -p, --prefix PREFIX               Remove PREFIX from all directory names
+      --no-prefix                   Do not remove prefix from directory names
+      --(no-)function-coverage      Enable (disable) function coverage display
+      --(no-)branch-coverage        Enable (disable) branch coverage display
+
+HTML output:
+  -f, --frames                      Use HTML frames for source code view
+  -t, --title TITLE                 Display TITLE in header of all pages
+  -c, --css-file CSSFILE            Use external style sheet file CSSFILE
+      --no-source                   Do not create source code view
+      --num-spaces NUM              Replace tabs with NUM spaces in source view
+      --highlight                   Highlight lines with converted-only data
+      --legend                      Include color legend in HTML output
+      --html-prolog FILE            Use FILE as HTML prolog for generated pages
+      --html-epilog FILE            Use FILE as HTML epilog for generated pages
+      --html-extension EXT          Use EXT as filename extension for pages
+      --html-gzip                   Use gzip to compress HTML
+      --(no-)sort                   Enable (disable) sorted coverage views
+      --demangle-cpp                Demangle C++ function names
+      --precision NUM               Set precision of coverage rate
+      --missed                      Show miss counts as negative numbers
+
+For more information see: $lcov_url
+END_OF_USAGE
+	;
+}
+
+
+#
+# get_rate(found, hit)
+#
+# Return a relative value for the specified found&hit values
+# which is used for sorting the corresponding entries in a
+# file list.
+#
+
+sub get_rate($$)
+{
+	my ($found, $hit) = @_;
+
+	if ($found == 0) {
+		return 10000;
+	}
+	return int($hit * 1000 / $found) * 10 + 2 - (1 / $found);
+}
+
+
+#
+# get_overall_line(found, hit, name_singular, name_plural)
+#
+# Return a string containing overall information for the specified
+# found/hit data.
+#
+
+sub get_overall_line($$$$)
+{
+	my ($found, $hit, $name_sn, $name_pl) = @_;
+	my $name;
+
+	return "no data found" if (!defined($found) || $found == 0);
+	$name = ($found == 1) ? $name_sn : $name_pl;
+	return rate($hit, $found, "% ($hit of $found $name)");
+}
+
+
+#
+# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
+#                    br_found, br_hit)
+#
+# Print overall coverage rates for the specified coverage types.
+#
+
+sub print_overall_rate($$$$$$$$$)
+{
+	my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
+	    $br_do, $br_found, $br_hit) = @_;
+
+	info("Overall coverage rate:\n");
+	info("  lines......: %s\n",
+	     get_overall_line($ln_found, $ln_hit, "line", "lines"))
+		if ($ln_do);
+	info("  functions..: %s\n",
+	     get_overall_line($fn_found, $fn_hit, "function", "functions"))
+		if ($fn_do);
+	info("  branches...: %s\n",
+	     get_overall_line($br_found, $br_hit, "branch", "branches"))
+		if ($br_do);
+}
+
+sub get_fn_list($)
+{
+	my ($info) = @_;
+	my %fns;
+	my @result;
+
+	foreach my $filename (keys(%{$info})) {
+		my $data = $info->{$filename};
+		my $funcdata = $data->{"func"};
+		my $sumfnccount = $data->{"sumfnc"};
+
+		if (defined($funcdata)) {
+			foreach my $func_name (keys(%{$funcdata})) {
+				$fns{$func_name} = 1;
+			}
+		}
+
+		if (defined($sumfnccount)) {
+			foreach my $func_name (keys(%{$sumfnccount})) {
+				$fns{$func_name} = 1;
+			}
+		}
+	}
+
+	@result = keys(%fns);
+
+	return \@result;
+}
+
+#
+# rename_functions(info, conv)
+#
+# Rename all function names in INFO according to CONV: OLD_NAME -> NEW_NAME.
+# In case two functions demangle to the same name, assume that they are
+# different object code implementations for the same source function.
+#
+
+sub rename_functions($$)
+{
+	my ($info, $conv) = @_;
+
+	foreach my $filename (keys(%{$info})) {
+		my $data = $info->{$filename};
+		my $funcdata;
+		my $testfncdata;
+		my $sumfnccount;
+		my %newfuncdata;
+		my %newsumfnccount;
+		my $f_found;
+		my $f_hit;
+
+		# funcdata: function name -> line number
+		$funcdata = $data->{"func"};
+		foreach my $fn (keys(%{$funcdata})) {
+			my $cn = $conv->{$fn};
+
+			# Abort if two functions on different lines map to the
+			# same demangled name.
+			if (defined($newfuncdata{$cn}) &&
+			    $newfuncdata{$cn} != $funcdata->{$fn}) {
+				die("ERROR: Demangled function name $cn ".
+				    "maps to different lines (".
+				    $newfuncdata{$cn}." vs ".
+				    $funcdata->{$fn}.") in $filename\n");
+			}
+			$newfuncdata{$cn} = $funcdata->{$fn};
+		}
+		$data->{"func"} = \%newfuncdata;
+
+		# testfncdata: test name -> testfnccount
+		# testfnccount: function name -> execution count
+		$testfncdata = $data->{"testfnc"};
+		foreach my $tn (keys(%{$testfncdata})) {
+			my $testfnccount = $testfncdata->{$tn};
+			my %newtestfnccount;
+
+			foreach my $fn (keys(%{$testfnccount})) {
+				my $cn = $conv->{$fn};
+
+				# Add counts for different functions that map
+				# to the same name.
+				$newtestfnccount{$cn} +=
+					$testfnccount->{$fn};
+			}
+			$testfncdata->{$tn} = \%newtestfnccount;
+		}
+
+		# sumfnccount: function name -> execution count
+		$sumfnccount = $data->{"sumfnc"};
+		foreach my $fn (keys(%{$sumfnccount})) {
+			my $cn = $conv->{$fn};
+
+			# Add counts for different functions that map
+			# to the same name.
+			$newsumfnccount{$cn} += $sumfnccount->{$fn};
+		}
+		$data->{"sumfnc"} = \%newsumfnccount;
+
+		# Update function found and hit counts since they may have
+		# changed
+		$f_found = 0;
+		$f_hit = 0;
+		foreach my $fn (keys(%newsumfnccount)) {
+			$f_found++;
+			$f_hit++ if ($newsumfnccount{$fn} > 0);
+		}
+		$data->{"f_found"} = $f_found;
+		$data->{"f_hit"} = $f_hit;
+	}
+}
+
+#
+# gen_html()
+#
+# Generate a set of HTML pages from contents of .info file INFO_FILENAME.
+# Files will be written to the current directory. If provided, test case
+# descriptions will be read from .tests file TEST_FILENAME and included
+# in ouput.
+#
+# Die on error.
+#
+
+sub gen_html()
+{
+	local *HTML_HANDLE;
+	my %overview;
+	my %base_data;
+	my $lines_found;
+	my $lines_hit;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+	my $overall_found = 0;
+	my $overall_hit = 0;
+	my $total_fn_found = 0;
+	my $total_fn_hit = 0;
+	my $total_br_found = 0;
+	my $total_br_hit = 0;
+	my $dir_name;
+	my $link_name;
+	my @dir_list;
+	my %new_info;
+
+	# Read in all specified .info files
+	foreach (@info_filenames)
+	{
+		%new_info = %{read_info_file($_)};
+
+		# Combine %new_info with %info_data
+		%info_data = %{combine_info_files(\%info_data, \%new_info)};
+	}
+
+	info("Found %d entries.\n", scalar(keys(%info_data)));
+
+	# Read and apply baseline data if specified
+	if ($base_filename)
+	{
+		# Read baseline file
+		info("Reading baseline file $base_filename\n");
+		%base_data = %{read_info_file($base_filename)};
+		info("Found %d entries.\n", scalar(keys(%base_data)));
+
+		# Apply baseline
+		info("Subtracting baseline data.\n");
+		%info_data = %{apply_baseline(\%info_data, \%base_data)};
+	}
+
+	@dir_list = get_dir_list(keys(%info_data));
+
+	if ($no_prefix)
+	{
+		# User requested that we leave filenames alone
+		info("User asked not to remove filename prefix\n");
+	}
+	elsif (! @dir_prefix)
+	{
+		# Get prefix common to most directories in list
+		my $prefix = get_prefix(1, keys(%info_data));
+
+		if ($prefix)
+		{
+			info("Found common filename prefix \"$prefix\"\n");
+			$dir_prefix[0] = $prefix;
+
+		}
+		else
+		{
+			info("No common filename prefix found!\n");
+			$no_prefix=1;
+		}
+	}
+	else
+	{
+		my $msg = "Using user-specified filename prefix ";
+		for my $i (0 .. $#dir_prefix)
+		{
+				$dir_prefix[$i] =~ s/\/+$//;
+				$msg .= ", " unless 0 == $i;
+				$msg .= "\"" . $dir_prefix[$i] . "\"";
+		}
+		info($msg . "\n");
+	}
+
+
+	# Read in test description file if specified
+	if ($desc_filename)
+	{
+		info("Reading test description file $desc_filename\n");
+		%test_description = %{read_testfile($desc_filename)};
+
+		# Remove test descriptions which are not referenced
+		# from %info_data if user didn't tell us otherwise
+		if (!$keep_descriptions)
+		{
+			remove_unused_descriptions();
+		}
+	}
+
+	# Change to output directory if specified
+	if ($output_directory)
+	{
+		chdir($output_directory)
+			or die("ERROR: cannot change to directory ".
+			"$output_directory!\n");
+	}
+
+	info("Writing .css and .png files.\n");
+	write_css_file();
+	write_png_files();
+
+	if ($html_gzip)
+	{
+		info("Writing .htaccess file.\n");
+		write_htaccess_file();
+	}
+
+	info("Generating output.\n");
+
+	# Process each subdirectory and collect overview information
+	foreach $dir_name (@dir_list)
+	{
+		($lines_found, $lines_hit, $fn_found, $fn_hit,
+		 $br_found, $br_hit)
+			= process_dir($dir_name);
+
+		# Handle files in root directory gracefully
+		$dir_name = "root" if ($dir_name eq "");
+
+		# Remove prefix if applicable
+		if (!$no_prefix && @dir_prefix)
+		{
+			# Match directory names beginning with one of @dir_prefix
+			$dir_name = apply_prefix($dir_name,@dir_prefix);
+		}
+
+		# Generate name for directory overview HTML page
+		if ($dir_name =~ /^\/(.*)$/)
+		{
+			$link_name = substr($dir_name, 1)."/index.$html_ext";
+		}
+		else
+		{
+			$link_name = $dir_name."/index.$html_ext";
+		}
+
+		$overview{$dir_name} = [$lines_found, $lines_hit, $fn_found,
+					$fn_hit, $br_found, $br_hit, $link_name,
+					get_rate($lines_found, $lines_hit),
+					get_rate($fn_found, $fn_hit),
+					get_rate($br_found, $br_hit)];
+		$overall_found	+= $lines_found;
+		$overall_hit	+= $lines_hit;
+		$total_fn_found	+= $fn_found;
+		$total_fn_hit	+= $fn_hit;
+		$total_br_found	+= $br_found;
+		$total_br_hit	+= $br_hit;
+	}
+
+	# Generate overview page
+	info("Writing directory view page.\n");
+
+	# Create sorted pages
+	foreach (@fileview_sortlist) {
+		write_dir_page($fileview_sortname[$_], ".", "", $test_title,
+			       undef, $overall_found, $overall_hit,
+			       $total_fn_found, $total_fn_hit, $total_br_found,
+			       $total_br_hit, \%overview, {}, {}, {}, 0, $_);
+	}
+
+	# Check if there are any test case descriptions to write out
+	if (%test_description)
+	{
+		info("Writing test case description file.\n");
+		write_description_file( \%test_description,
+					$overall_found, $overall_hit,
+					$total_fn_found, $total_fn_hit,
+					$total_br_found, $total_br_hit);
+	}
+
+	print_overall_rate(1, $overall_found, $overall_hit,
+			   $func_coverage, $total_fn_found, $total_fn_hit,
+			   $br_coverage, $total_br_found, $total_br_hit);
+
+	chdir($cwd);
+}
+
+#
+# html_create(handle, filename)
+#
+
+sub html_create($$)
+{
+	my $handle = $_[0];
+	my $filename = $_[1];
+
+	if ($html_gzip)
+	{
+		open($handle, "|-", "gzip -c >'$filename'")
+			or die("ERROR: cannot open $filename for writing ".
+			       "(gzip)!\n");
+	}
+	else
+	{
+		open($handle, ">", $filename)
+			or die("ERROR: cannot open $filename for writing!\n");
+	}
+}
+
+sub write_dir_page($$$$$$$$$$$$$$$$$)
+{
+	my ($name, $rel_dir, $base_dir, $title, $trunc_dir, $overall_found,
+	    $overall_hit, $total_fn_found, $total_fn_hit, $total_br_found,
+	    $total_br_hit, $overview, $testhash, $testfnchash, $testbrhash,
+	    $view_type, $sort_type) = @_;
+
+	# Generate directory overview page including details
+	html_create(*HTML_HANDLE, "$rel_dir/index$name.$html_ext");
+	if (!defined($trunc_dir)) {
+		$trunc_dir = "";
+	}
+	$title .= " - " if ($trunc_dir ne "");
+	write_html_prolog(*HTML_HANDLE, $base_dir, "LCOV - $title$trunc_dir");
+	write_header(*HTML_HANDLE, $view_type, $trunc_dir, $rel_dir,
+		     $overall_found, $overall_hit, $total_fn_found,
+		     $total_fn_hit, $total_br_found, $total_br_hit, $sort_type);
+	write_file_table(*HTML_HANDLE, $base_dir, $overview, $testhash,
+			 $testfnchash, $testbrhash, $view_type, $sort_type);
+	write_html_epilog(*HTML_HANDLE, $base_dir);
+	close(*HTML_HANDLE);
+}
+
+
+#
+# process_dir(dir_name)
+#
+
+sub process_dir($)
+{
+	my $abs_dir = $_[0];
+	my $trunc_dir;
+	my $rel_dir = $abs_dir;
+	my $base_dir;
+	my $filename;
+	my %overview;
+	my $lines_found;
+	my $lines_hit;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+	my $overall_found=0;
+	my $overall_hit=0;
+	my $total_fn_found=0;
+	my $total_fn_hit=0;
+	my $total_br_found = 0;
+	my $total_br_hit = 0;
+	my $base_name;
+	my $extension;
+	my $testdata;
+	my %testhash;
+	my $testfncdata;
+	my %testfnchash;
+	my $testbrdata;
+	my %testbrhash;
+	my @sort_list;
+	local *HTML_HANDLE;
+
+	# Remove prefix if applicable
+	if (!$no_prefix)
+	{
+		# Match directory name beginning with one of @dir_prefix
+		$rel_dir = apply_prefix($rel_dir,@dir_prefix);
+	}
+
+	$trunc_dir = $rel_dir;
+
+	# Remove leading /
+	if ($rel_dir =~ /^\/(.*)$/)
+	{
+		$rel_dir = substr($rel_dir, 1);
+	}
+
+	# Handle files in root directory gracefully
+	$rel_dir = "root" if ($rel_dir eq "");
+	$trunc_dir = "root" if ($trunc_dir eq "");
+
+	$base_dir = get_relative_base_path($rel_dir);
+
+	create_sub_dir($rel_dir);
+
+	# Match filenames which specify files in this directory, not including
+	# sub-directories
+	foreach $filename (grep(/^\Q$abs_dir\E\/[^\/]*$/,keys(%info_data)))
+	{
+		my $page_link;
+		my $func_link;
+
+		($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
+		 $br_hit, $testdata, $testfncdata, $testbrdata) =
+			process_file($trunc_dir, $rel_dir, $filename);
+
+		$base_name = basename($filename);
+
+		if ($no_sourceview) {
+			$page_link = "";
+		} elsif ($frames) {
+			# Link to frameset page
+			$page_link = "$base_name.gcov.frameset.$html_ext";
+		} else {
+			# Link directory to source code view page
+			$page_link = "$base_name.gcov.$html_ext";
+		}
+		$overview{$base_name} = [$lines_found, $lines_hit, $fn_found,
+					 $fn_hit, $br_found, $br_hit,
+					 $page_link,
+					 get_rate($lines_found, $lines_hit),
+					 get_rate($fn_found, $fn_hit),
+					 get_rate($br_found, $br_hit)];
+
+		$testhash{$base_name} = $testdata;
+		$testfnchash{$base_name} = $testfncdata;
+		$testbrhash{$base_name} = $testbrdata;
+
+		$overall_found	+= $lines_found;
+		$overall_hit	+= $lines_hit;
+
+		$total_fn_found += $fn_found;
+		$total_fn_hit   += $fn_hit;
+
+		$total_br_found += $br_found;
+		$total_br_hit   += $br_hit;
+	}
+
+	# Create sorted pages
+	foreach (@fileview_sortlist) {
+		# Generate directory overview page (without details)	
+		write_dir_page($fileview_sortname[$_], $rel_dir, $base_dir,
+			       $test_title, $trunc_dir, $overall_found,
+			       $overall_hit, $total_fn_found, $total_fn_hit,
+			       $total_br_found, $total_br_hit, \%overview, {},
+			       {}, {}, 1, $_);
+		if (!$show_details) {
+			next;
+		}
+		# Generate directory overview page including details
+		write_dir_page("-detail".$fileview_sortname[$_], $rel_dir,
+			       $base_dir, $test_title, $trunc_dir,
+			       $overall_found, $overall_hit, $total_fn_found,
+			       $total_fn_hit, $total_br_found, $total_br_hit,
+			       \%overview, \%testhash, \%testfnchash,
+			       \%testbrhash, 1, $_);
+	}
+
+	# Calculate resulting line counts
+	return ($overall_found, $overall_hit, $total_fn_found, $total_fn_hit,
+		$total_br_found, $total_br_hit);
+}
+
+
+#
+# get_converted_lines(testdata)
+#
+# Return hash of line numbers of those lines which were only covered in
+# converted data sets.
+#
+
+sub get_converted_lines($)
+{
+	my $testdata = $_[0];
+	my $testcount;
+	my %converted;
+	my %nonconverted;
+	my $hash;
+	my $testcase;
+	my $line;
+	my %result;
+
+
+	# Get a hash containing line numbers with positive counts both for
+	# converted and original data sets
+	foreach $testcase (keys(%{$testdata}))
+	{
+		# Check to see if this is a converted data set
+		if ($testcase =~ /,diff$/)
+		{
+			$hash = \%converted;
+		}
+		else
+		{
+			$hash = \%nonconverted;
+		}
+
+		$testcount = $testdata->{$testcase};
+		# Add lines with a positive count to hash
+		foreach $line (keys%{$testcount})
+		{
+			if ($testcount->{$line} > 0)
+			{
+				$hash->{$line} = 1;
+			}
+		}
+	}
+
+	# Combine both hashes to resulting list
+	foreach $line (keys(%converted))
+	{
+		if (!defined($nonconverted{$line}))
+		{
+			$result{$line} = 1;
+		}
+	}
+
+	return \%result;
+}
+
+
+sub write_function_page($$$$$$$$$$$$$$$$$$)
+{
+	my ($base_dir, $rel_dir, $trunc_dir, $base_name, $title,
+	    $lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, $br_hit,
+	    $sumcount, $funcdata, $sumfnccount, $testfncdata, $sumbrcount,
+	    $testbrdata, $sort_type) = @_;
+	my $pagetitle;
+	my $filename;
+
+	# Generate function table for this file
+	if ($sort_type == 0) {
+		$filename = "$rel_dir/$base_name.func.$html_ext";
+	} else {
+		$filename = "$rel_dir/$base_name.func-sort-c.$html_ext";
+	}
+	html_create(*HTML_HANDLE, $filename);
+	$pagetitle = "LCOV - $title - $trunc_dir/$base_name - functions";
+	write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
+	write_header(*HTML_HANDLE, 4, "$trunc_dir/$base_name",
+		     "$rel_dir/$base_name", $lines_found, $lines_hit,
+		     $fn_found, $fn_hit, $br_found, $br_hit, $sort_type);
+	write_function_table(*HTML_HANDLE, "$base_name.gcov.$html_ext",
+			     $sumcount, $funcdata,
+			     $sumfnccount, $testfncdata, $sumbrcount,
+			     $testbrdata, $base_name,
+			     $base_dir, $sort_type);
+	write_html_epilog(*HTML_HANDLE, $base_dir, 1);
+	close(*HTML_HANDLE);
+}
+
+
+#
+# process_file(trunc_dir, rel_dir, filename)
+#
+
+sub process_file($$$)
+{
+	info("Processing file ".apply_prefix($_[2], @dir_prefix)."\n");
+
+	my $trunc_dir = $_[0];
+	my $rel_dir = $_[1];
+	my $filename = $_[2];
+	my $base_name = basename($filename);
+	my $base_dir = get_relative_base_path($rel_dir);
+	my $testdata;
+	my $testcount;
+	my $sumcount;
+	my $funcdata;
+	my $checkdata;
+	my $testfncdata;
+	my $sumfnccount;
+	my $testbrdata;
+	my $sumbrcount;
+	my $lines_found;
+	my $lines_hit;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+	my $converted;
+	my @source;
+	my $pagetitle;
+	local *HTML_HANDLE;
+
+	($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
+	 $sumfnccount, $testbrdata, $sumbrcount, $lines_found, $lines_hit,
+	 $fn_found, $fn_hit, $br_found, $br_hit)
+		= get_info_entry($info_data{$filename});
+
+	# Return after this point in case user asked us not to generate
+	# source code view
+	if ($no_sourceview)
+	{
+		return ($lines_found, $lines_hit, $fn_found, $fn_hit,
+			$br_found, $br_hit, $testdata, $testfncdata,
+			$testbrdata);
+	}
+
+	$converted = get_converted_lines($testdata);
+	# Generate source code view for this file
+	html_create(*HTML_HANDLE, "$rel_dir/$base_name.gcov.$html_ext");
+	$pagetitle = "LCOV - $test_title - $trunc_dir/$base_name";
+	write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
+	write_header(*HTML_HANDLE, 2, "$trunc_dir/$base_name",
+		     "$rel_dir/$base_name", $lines_found, $lines_hit,
+		     $fn_found, $fn_hit, $br_found, $br_hit, 0);
+	@source = write_source(*HTML_HANDLE, $filename, $sumcount, $checkdata,
+			       $converted, $funcdata, $sumbrcount);
+
+	write_html_epilog(*HTML_HANDLE, $base_dir, 1);
+	close(*HTML_HANDLE);
+
+	if ($func_coverage) {
+		# Create function tables
+		foreach (@funcview_sortlist) {
+			write_function_page($base_dir, $rel_dir, $trunc_dir,
+					    $base_name, $test_title,
+					    $lines_found, $lines_hit,
+					    $fn_found, $fn_hit, $br_found,
+					    $br_hit, $sumcount,
+					    $funcdata, $sumfnccount,
+					    $testfncdata, $sumbrcount,
+					    $testbrdata, $_);
+		}
+	}
+
+	# Additional files are needed in case of frame output
+	if (!$frames)
+	{
+		return ($lines_found, $lines_hit, $fn_found, $fn_hit,
+			$br_found, $br_hit, $testdata, $testfncdata,
+			$testbrdata);
+	}
+
+	# Create overview png file
+	gen_png("$rel_dir/$base_name.gcov.png", $overview_width, $tab_size,
+		@source);
+
+	# Create frameset page
+	html_create(*HTML_HANDLE,
+		    "$rel_dir/$base_name.gcov.frameset.$html_ext");
+	write_frameset(*HTML_HANDLE, $base_dir, $base_name, $pagetitle);
+	close(*HTML_HANDLE);
+
+	# Write overview frame
+	html_create(*HTML_HANDLE,
+		    "$rel_dir/$base_name.gcov.overview.$html_ext");
+	write_overview(*HTML_HANDLE, $base_dir, $base_name, $pagetitle,
+		       scalar(@source));
+	close(*HTML_HANDLE);
+
+	return ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
+		$br_hit, $testdata, $testfncdata, $testbrdata);
+}
+
+
+sub compress_brcount($)
+{
+	my ($brcount) = @_;
+	my $db;
+
+	$db = brcount_to_db($brcount);
+	return db_to_brcount($db, $brcount);
+}
+
+
+#
+# read_info_file(info_filename)
+#
+# Read in the contents of the .info file specified by INFO_FILENAME. Data will
+# be returned as a reference to a hash containing the following mappings:
+#
+# %result: for each filename found in file -> \%data
+#
+# %data: "test"  -> \%testdata
+#        "sum"   -> \%sumcount
+#        "func"  -> \%funcdata
+#        "found" -> $lines_found (number of instrumented lines found in file)
+#	 "hit"   -> $lines_hit (number of executed lines in file)
+#        "f_found" -> $fn_found (number of instrumented functions found in file)
+#	 "f_hit"   -> $fn_hit (number of executed functions in file)
+#        "b_found" -> $br_found (number of instrumented branches found in file)
+#	 "b_hit"   -> $br_hit (number of executed branches in file)
+#        "check" -> \%checkdata
+#        "testfnc" -> \%testfncdata
+#        "sumfnc"  -> \%sumfnccount
+#        "testbr"  -> \%testbrdata
+#        "sumbr"   -> \%sumbrcount
+#
+# %testdata   : name of test affecting this file -> \%testcount
+# %testfncdata: name of test affecting this file -> \%testfnccount
+# %testbrdata:  name of test affecting this file -> \%testbrcount
+#
+# %testcount   : line number   -> execution count for a single test
+# %testfnccount: function name -> execution count for a single test
+# %testbrcount : line number   -> branch coverage data for a single test
+# %sumcount    : line number   -> execution count for all tests
+# %sumfnccount : function name -> execution count for all tests
+# %sumbrcount  : line number   -> branch coverage data for all tests
+# %funcdata    : function name -> line number
+# %checkdata   : line number   -> checksum of source code line
+# $brdata      : vector of items: block, branch, taken
+# 
+# Note that .info file sections referring to the same file and test name
+# will automatically be combined by adding all execution counts.
+#
+# Note that if INFO_FILENAME ends with ".gz", it is assumed that the file
+# is compressed using GZIP. If available, GUNZIP will be used to decompress
+# this file.
+#
+# Die on error.
+#
+
+sub read_info_file($)
+{
+	my $tracefile = $_[0];		# Name of tracefile
+	my %result;			# Resulting hash: file -> data
+	my $data;			# Data handle for current entry
+	my $testdata;			#       "             "
+	my $testcount;			#       "             "
+	my $sumcount;			#       "             "
+	my $funcdata;			#       "             "
+	my $checkdata;			#       "             "
+	my $testfncdata;
+	my $testfnccount;
+	my $sumfnccount;
+	my $testbrdata;
+	my $testbrcount;
+	my $sumbrcount;
+	my $line;			# Current line read from .info file
+	my $testname;			# Current test name
+	my $filename;			# Current filename
+	my $hitcount;			# Count for lines hit
+	my $count;			# Execution count of current line
+	my $negative;			# If set, warn about negative counts
+	my $changed_testname;		# If set, warn about changed testname
+	my $line_checksum;		# Checksum of current line
+	my $notified_about_relative_paths;
+	local *INFO_HANDLE;		# Filehandle for .info file
+
+	info("Reading data file $tracefile\n");
+
+	# Check if file exists and is readable
+	stat($_[0]);
+	if (!(-r _))
+	{
+		die("ERROR: cannot read file $_[0]!\n");
+	}
+
+	# Check if this is really a plain file
+	if (!(-f _))
+	{
+		die("ERROR: not a plain file: $_[0]!\n");
+	}
+
+	# Check for .gz extension
+	if ($_[0] =~ /\.gz$/)
+	{
+		# Check for availability of GZIP tool
+		system_no_output(1, "gunzip" ,"-h")
+			and die("ERROR: gunzip command not available!\n");
+
+		# Check integrity of compressed file
+		system_no_output(1, "gunzip", "-t", $_[0])
+			and die("ERROR: integrity check failed for ".
+				"compressed file $_[0]!\n");
+
+		# Open compressed file
+		open(INFO_HANDLE, "-|", "gunzip -c '$_[0]'")
+			or die("ERROR: cannot start gunzip to decompress ".
+			       "file $_[0]!\n");
+	}
+	else
+	{
+		# Open decompressed file
+		open(INFO_HANDLE, "<", $_[0])
+			or die("ERROR: cannot read file $_[0]!\n");
+	}
+
+	$testname = "";
+	while (<INFO_HANDLE>)
+	{
+		chomp($_);
+		$line = $_;
+
+		# Switch statement
+		foreach ($line)
+		{
+			/^TN:([^,]*)(,diff)?/ && do
+			{
+				# Test name information found
+				$testname = defined($1) ? $1 : "";
+				if ($testname =~ s/\W/_/g)
+				{
+					$changed_testname = 1;
+				}
+				$testname .= $2 if (defined($2));
+				last;
+			};
+
+			/^[SK]F:(.*)/ && do
+			{
+				# Filename information found
+				# Retrieve data for new entry
+				$filename = File::Spec->rel2abs($1, $cwd);
+
+				if (!File::Spec->file_name_is_absolute($1) &&
+				    !$notified_about_relative_paths)
+				{
+					info("Resolved relative source file ".
+					     "path \"$1\" with CWD to ".
+					     "\"$filename\".\n");
+					$notified_about_relative_paths = 1;
+				}
+
+				$data = $result{$filename};
+				($testdata, $sumcount, $funcdata, $checkdata,
+				 $testfncdata, $sumfnccount, $testbrdata,
+				 $sumbrcount) =
+					get_info_entry($data);
+
+				if (defined($testname))
+				{
+					$testcount = $testdata->{$testname};
+					$testfnccount = $testfncdata->{$testname};
+					$testbrcount = $testbrdata->{$testname};
+				}
+				else
+				{
+					$testcount = {};
+					$testfnccount = {};
+					$testbrcount = {};
+				}
+				last;
+			};
+
+			/^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do
+			{
+				# Fix negative counts
+				$count = $2 < 0 ? 0 : $2;
+				if ($2 < 0)
+				{
+					$negative = 1;
+				}
+				# Execution count found, add to structure
+				# Add summary counts
+				$sumcount->{$1} += $count;
+
+				# Add test-specific counts
+				if (defined($testname))
+				{
+					$testcount->{$1} += $count;
+				}
+
+				# Store line checksum if available
+				if (defined($3))
+				{
+					$line_checksum = substr($3, 1);
+
+					# Does it match a previous definition
+					if (defined($checkdata->{$1}) &&
+					    ($checkdata->{$1} ne
+					     $line_checksum))
+					{
+						die("ERROR: checksum mismatch ".
+						    "at $filename:$1\n");
+					}
+
+					$checkdata->{$1} = $line_checksum;
+				}
+				last;
+			};
+
+			/^FN:(\d+),([^,]+)/ && do
+			{
+				last if (!$func_coverage);
+
+				# Function data found, add to structure
+				$funcdata->{$2} = $1;
+
+				# Also initialize function call data
+				if (!defined($sumfnccount->{$2})) {
+					$sumfnccount->{$2} = 0;
+				}
+				if (defined($testname))
+				{
+					if (!defined($testfnccount->{$2})) {
+						$testfnccount->{$2} = 0;
+					}
+				}
+				last;
+			};
+
+			/^FNDA:(\d+),([^,]+)/ && do
+			{
+				last if (!$func_coverage);
+				# Function call count found, add to structure
+				# Add summary counts
+				$sumfnccount->{$2} += $1;
+
+				# Add test-specific counts
+				if (defined($testname))
+				{
+					$testfnccount->{$2} += $1;
+				}
+				last;
+			};
+
+			/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
+				# Branch coverage data found
+				my ($line, $block, $branch, $taken) =
+				   ($1, $2, $3, $4);
+
+				last if (!$br_coverage);
+				$sumbrcount->{$line} .=
+					"$block,$branch,$taken:";
+
+				# Add test-specific counts
+				if (defined($testname)) {
+					$testbrcount->{$line} .=
+						"$block,$branch,$taken:";
+				}
+				last;
+			};
+
+			/^end_of_record/ && do
+			{
+				# Found end of section marker
+				if ($filename)
+				{
+					# Store current section data
+					if (defined($testname))
+					{
+						$testdata->{$testname} =
+							$testcount;
+						$testfncdata->{$testname} =
+							$testfnccount;
+						$testbrdata->{$testname} =
+							$testbrcount;
+					}	
+
+					set_info_entry($data, $testdata,
+						       $sumcount, $funcdata,
+						       $checkdata, $testfncdata,
+						       $sumfnccount,
+						       $testbrdata,
+						       $sumbrcount);
+					$result{$filename} = $data;
+					last;
+				}
+			};
+
+			# default
+			last;
+		}
+	}
+	close(INFO_HANDLE);
+
+	# Calculate lines_found and lines_hit for each file
+	foreach $filename (keys(%result))
+	{
+		$data = $result{$filename};
+
+		($testdata, $sumcount, undef, undef, $testfncdata,
+		 $sumfnccount, $testbrdata, $sumbrcount) =
+			get_info_entry($data);
+
+		# Filter out empty files
+		if (scalar(keys(%{$sumcount})) == 0)
+		{
+			delete($result{$filename});
+			next;
+		}
+		# Filter out empty test cases
+		foreach $testname (keys(%{$testdata}))
+		{
+			if (!defined($testdata->{$testname}) ||
+			    scalar(keys(%{$testdata->{$testname}})) == 0)
+			{
+				delete($testdata->{$testname});
+				delete($testfncdata->{$testname});
+			}
+		}
+
+		$data->{"found"} = scalar(keys(%{$sumcount}));
+		$hitcount = 0;
+
+		foreach (keys(%{$sumcount}))
+		{
+			if ($sumcount->{$_} > 0) { $hitcount++; }
+		}
+
+		$data->{"hit"} = $hitcount;
+
+		# Get found/hit values for function call data
+		$data->{"f_found"} = scalar(keys(%{$sumfnccount}));
+		$hitcount = 0;
+
+		foreach (keys(%{$sumfnccount})) {
+			if ($sumfnccount->{$_} > 0) {
+				$hitcount++;
+			}
+		}
+		$data->{"f_hit"} = $hitcount;
+
+		# Combine branch data for the same branches
+		(undef, $data->{"b_found"}, $data->{"b_hit"}) =
+			compress_brcount($sumbrcount);
+		foreach $testname (keys(%{$testbrdata})) {
+			compress_brcount($testbrdata->{$testname});
+		}
+	}
+
+	if (scalar(keys(%result)) == 0)
+	{
+		die("ERROR: no valid records found in tracefile $tracefile\n");
+	}
+	if ($negative)
+	{
+		warn("WARNING: negative counts found in tracefile ".
+		     "$tracefile\n");
+	}
+	if ($changed_testname)
+	{
+		warn("WARNING: invalid characters removed from testname in ".
+		     "tracefile $tracefile\n");
+	}
+
+	return(\%result);
+}
+
+
+#
+# get_info_entry(hash_ref)
+#
+# Retrieve data from an entry of the structure generated by read_info_file().
+# Return a list of references to hashes:
+# (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
+#  ref, testfncdata hash ref, sumfnccount hash ref, lines found, lines hit,
+#  functions found, functions hit)
+#
+
+sub get_info_entry($)
+{
+	my $testdata_ref = $_[0]->{"test"};
+	my $sumcount_ref = $_[0]->{"sum"};
+	my $funcdata_ref = $_[0]->{"func"};
+	my $checkdata_ref = $_[0]->{"check"};
+	my $testfncdata = $_[0]->{"testfnc"};
+	my $sumfnccount = $_[0]->{"sumfnc"};
+	my $testbrdata = $_[0]->{"testbr"};
+	my $sumbrcount = $_[0]->{"sumbr"};
+	my $lines_found = $_[0]->{"found"};
+	my $lines_hit = $_[0]->{"hit"};
+	my $fn_found = $_[0]->{"f_found"};
+	my $fn_hit = $_[0]->{"f_hit"};
+	my $br_found = $_[0]->{"b_found"};
+	my $br_hit = $_[0]->{"b_hit"};
+
+	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
+		$testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
+		$lines_found, $lines_hit, $fn_found, $fn_hit,
+		$br_found, $br_hit);
+}
+
+
+#
+# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
+#                checkdata_ref, testfncdata_ref, sumfcncount_ref,
+#                testbrdata_ref, sumbrcount_ref[,lines_found,
+#                lines_hit, f_found, f_hit, $b_found, $b_hit])
+#
+# Update the hash referenced by HASH_REF with the provided data references.
+#
+
+sub set_info_entry($$$$$$$$$;$$$$$$)
+{
+	my $data_ref = $_[0];
+
+	$data_ref->{"test"} = $_[1];
+	$data_ref->{"sum"} = $_[2];
+	$data_ref->{"func"} = $_[3];
+	$data_ref->{"check"} = $_[4];
+	$data_ref->{"testfnc"} = $_[5];
+	$data_ref->{"sumfnc"} = $_[6];
+	$data_ref->{"testbr"} = $_[7];
+	$data_ref->{"sumbr"} = $_[8];
+
+	if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
+	if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
+	if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
+	if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
+	if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
+	if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
+}
+
+
+#
+# add_counts(data1_ref, data2_ref)
+#
+# DATA1_REF and DATA2_REF are references to hashes containing a mapping
+#
+#   line number -> execution count
+#
+# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
+# is a reference to a hash containing the combined mapping in which
+# execution counts are added.
+#
+
+sub add_counts($$)
+{
+	my $data1_ref = $_[0];	# Hash 1
+	my $data2_ref = $_[1];	# Hash 2
+	my %result;		# Resulting hash
+	my $line;		# Current line iteration scalar
+	my $data1_count;	# Count of line in hash1
+	my $data2_count;	# Count of line in hash2
+	my $found = 0;		# Total number of lines found
+	my $hit = 0;		# Number of lines with a count > 0
+
+	foreach $line (keys(%$data1_ref))
+	{
+		$data1_count = $data1_ref->{$line};
+		$data2_count = $data2_ref->{$line};
+
+		# Add counts if present in both hashes
+		if (defined($data2_count)) { $data1_count += $data2_count; }
+
+		# Store sum in %result
+		$result{$line} = $data1_count;
+
+		$found++;
+		if ($data1_count > 0) { $hit++; }
+	}
+
+	# Add lines unique to data2_ref
+	foreach $line (keys(%$data2_ref))
+	{
+		# Skip lines already in data1_ref
+		if (defined($data1_ref->{$line})) { next; }
+
+		# Copy count from data2_ref
+		$result{$line} = $data2_ref->{$line};
+
+		$found++;
+		if ($result{$line} > 0) { $hit++; }
+	}
+
+	return (\%result, $found, $hit);
+}
+
+
+#
+# merge_checksums(ref1, ref2, filename)
+#
+# REF1 and REF2 are references to hashes containing a mapping
+#
+#   line number -> checksum
+#
+# Merge checksum lists defined in REF1 and REF2 and return reference to
+# resulting hash. Die if a checksum for a line is defined in both hashes
+# but does not match.
+#
+
+sub merge_checksums($$$)
+{
+	my $ref1 = $_[0];
+	my $ref2 = $_[1];
+	my $filename = $_[2];
+	my %result;
+	my $line;
+
+	foreach $line (keys(%{$ref1}))
+	{
+		if (defined($ref2->{$line}) &&
+		    ($ref1->{$line} ne $ref2->{$line}))
+		{
+			die("ERROR: checksum mismatch at $filename:$line\n");
+		}
+		$result{$line} = $ref1->{$line};
+	}
+
+	foreach $line (keys(%{$ref2}))
+	{
+		$result{$line} = $ref2->{$line};
+	}
+
+	return \%result;
+}
+
+
+#
+# merge_func_data(funcdata1, funcdata2, filename)
+#
+
+sub merge_func_data($$$)
+{
+	my ($funcdata1, $funcdata2, $filename) = @_;
+	my %result;
+	my $func;
+
+	if (defined($funcdata1)) {
+		%result = %{$funcdata1};
+	}
+
+	foreach $func (keys(%{$funcdata2})) {
+		my $line1 = $result{$func};
+		my $line2 = $funcdata2->{$func};
+
+		if (defined($line1) && ($line1 != $line2)) {
+			warn("WARNING: function data mismatch at ".
+			     "$filename:$line2\n");
+			next;
+		}
+		$result{$func} = $line2;
+	}
+
+	return \%result;
+}
+
+
+#
+# add_fnccount(fnccount1, fnccount2)
+#
+# Add function call count data. Return list (fnccount_added, f_found, f_hit)
+#
+
+sub add_fnccount($$)
+{
+	my ($fnccount1, $fnccount2) = @_;
+	my %result;
+	my $fn_found;
+	my $fn_hit;
+	my $function;
+
+	if (defined($fnccount1)) {
+		%result = %{$fnccount1};
+	}
+	foreach $function (keys(%{$fnccount2})) {
+		$result{$function} += $fnccount2->{$function};
+	}
+	$fn_found = scalar(keys(%result));
+	$fn_hit = 0;
+	foreach $function (keys(%result)) {
+		if ($result{$function} > 0) {
+			$fn_hit++;
+		}
+	}
+
+	return (\%result, $fn_found, $fn_hit);
+}
+
+#
+# add_testfncdata(testfncdata1, testfncdata2)
+#
+# Add function call count data for several tests. Return reference to
+# added_testfncdata.
+#
+
+sub add_testfncdata($$)
+{
+	my ($testfncdata1, $testfncdata2) = @_;
+	my %result;
+	my $testname;
+
+	foreach $testname (keys(%{$testfncdata1})) {
+		if (defined($testfncdata2->{$testname})) {
+			my $fnccount;
+
+			# Function call count data for this testname exists
+			# in both data sets: add
+			($fnccount) = add_fnccount(
+				$testfncdata1->{$testname},
+				$testfncdata2->{$testname});
+			$result{$testname} = $fnccount;
+			next;
+		}
+		# Function call count data for this testname is unique to
+		# data set 1: copy
+		$result{$testname} = $testfncdata1->{$testname};
+	}
+
+	# Add count data for testnames unique to data set 2
+	foreach $testname (keys(%{$testfncdata2})) {
+		if (!defined($result{$testname})) {
+			$result{$testname} = $testfncdata2->{$testname};
+		}
+	}
+	return \%result;
+}
+
+
+#
+# brcount_to_db(brcount)
+#
+# Convert brcount data to the following format:
+#
+# db:          line number    -> block hash
+# block hash:  block number   -> branch hash
+# branch hash: branch number  -> taken value
+#
+
+sub brcount_to_db($)
+{
+	my ($brcount) = @_;
+	my $line;
+	my $db;
+
+	# Add branches to database
+	foreach $line (keys(%{$brcount})) {
+		my $brdata = $brcount->{$line};
+
+		foreach my $entry (split(/:/, $brdata)) {
+			my ($block, $branch, $taken) = split(/,/, $entry);
+			my $old = $db->{$line}->{$block}->{$branch};
+
+			if (!defined($old) || $old eq "-") {
+				$old = $taken;
+			} elsif ($taken ne "-") {
+				$old += $taken;
+			}
+
+			$db->{$line}->{$block}->{$branch} = $old;
+		}
+	}
+
+	return $db;
+}
+
+
+#
+# db_to_brcount(db[, brcount])
+#
+# Convert branch coverage data back to brcount format. If brcount is specified,
+# the converted data is directly inserted in brcount.
+#
+
+sub db_to_brcount($;$)
+{
+	my ($db, $brcount) = @_;
+	my $line;
+	my $br_found = 0;
+	my $br_hit = 0;
+
+	# Convert database back to brcount format
+	foreach $line (sort({$a <=> $b} keys(%{$db}))) {
+		my $ldata = $db->{$line};
+		my $brdata;
+		my $block;
+
+		foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
+			my $bdata = $ldata->{$block};
+			my $branch;
+
+			foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
+				my $taken = $bdata->{$branch};
+
+				$br_found++;
+				$br_hit++ if ($taken ne "-" && $taken > 0);
+				$brdata .= "$block,$branch,$taken:";
+			}
+		}
+		$brcount->{$line} = $brdata;
+	}
+
+	return ($brcount, $br_found, $br_hit);
+}
+
+
+#
+# brcount_db_combine(db1, db2, op)
+#
+# db1 := db1 op db2, where
+#   db1, db2: brcount data as returned by brcount_to_db
+#   op:       one of $BR_ADD and BR_SUB
+#
+sub brcount_db_combine($$$)
+{
+	my ($db1, $db2, $op) = @_;
+
+	foreach my $line (keys(%{$db2})) {
+		my $ldata = $db2->{$line};
+
+		foreach my $block (keys(%{$ldata})) {
+			my $bdata = $ldata->{$block};
+
+			foreach my $branch (keys(%{$bdata})) {
+				my $taken = $bdata->{$branch};
+				my $new = $db1->{$line}->{$block}->{$branch};
+
+				if (!defined($new) || $new eq "-") {
+					$new = $taken;
+				} elsif ($taken ne "-") {
+					if ($op == $BR_ADD) {
+						$new += $taken;
+					} elsif ($op == $BR_SUB) {
+						$new -= $taken;
+						$new = 0 if ($new < 0);
+					}
+				}
+
+				$db1->{$line}->{$block}->{$branch} = $new;
+			}
+		}
+	}
+}
+
+
+#
+# brcount_db_get_found_and_hit(db)
+#
+# Return (br_found, br_hit) for db.
+#
+
+sub brcount_db_get_found_and_hit($)
+{
+	my ($db) = @_;
+	my ($br_found , $br_hit) = (0, 0);
+
+	foreach my $line (keys(%{$db})) {
+		my $ldata = $db->{$line};
+
+		foreach my $block (keys(%{$ldata})) {
+			my $bdata = $ldata->{$block};
+
+			foreach my $branch (keys(%{$bdata})) {
+				my $taken = $bdata->{$branch};
+
+				$br_found++;
+				$br_hit++ if ($taken ne "-" && $taken > 0);
+			}
+		}
+	}
+
+	return ($br_found, $br_hit);
+}
+
+
+# combine_brcount(brcount1, brcount2, type, inplace)
+#
+# If add is BR_ADD, add branch coverage data and return list brcount_added.
+# If add is BR_SUB, subtract the taken values of brcount2 from brcount1 and
+# return brcount_sub. If inplace is set, the result is inserted into brcount1.
+#
+
+sub combine_brcount($$$;$)
+{
+	my ($brcount1, $brcount2, $type, $inplace) = @_;
+	my ($db1, $db2);
+
+	$db1 = brcount_to_db($brcount1);
+	$db2 = brcount_to_db($brcount2);
+	brcount_db_combine($db1, $db2, $type);
+
+	return db_to_brcount($db1, $inplace ? $brcount1 : undef);
+}
+
+
+#
+# add_testbrdata(testbrdata1, testbrdata2)
+#
+# Add branch coverage data for several tests. Return reference to
+# added_testbrdata.
+#
+
+sub add_testbrdata($$)
+{
+	my ($testbrdata1, $testbrdata2) = @_;
+	my %result;
+	my $testname;
+
+	foreach $testname (keys(%{$testbrdata1})) {
+		if (defined($testbrdata2->{$testname})) {
+			my $brcount;
+
+			# Branch coverage data for this testname exists
+			# in both data sets: add
+			($brcount) = combine_brcount($testbrdata1->{$testname},
+					 $testbrdata2->{$testname}, $BR_ADD);
+			$result{$testname} = $brcount;
+			next;
+		}
+		# Branch coverage data for this testname is unique to
+		# data set 1: copy
+		$result{$testname} = $testbrdata1->{$testname};
+	}
+
+	# Add count data for testnames unique to data set 2
+	foreach $testname (keys(%{$testbrdata2})) {
+		if (!defined($result{$testname})) {
+			$result{$testname} = $testbrdata2->{$testname};
+		}
+	}
+	return \%result;
+}
+
+
+#
+# combine_info_entries(entry_ref1, entry_ref2, filename)
+#
+# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
+# Return reference to resulting hash.
+#
+
+sub combine_info_entries($$$)
+{
+	my $entry1 = $_[0];	# Reference to hash containing first entry
+	my $testdata1;
+	my $sumcount1;
+	my $funcdata1;
+	my $checkdata1;
+	my $testfncdata1;
+	my $sumfnccount1;
+	my $testbrdata1;
+	my $sumbrcount1;
+
+	my $entry2 = $_[1];	# Reference to hash containing second entry
+	my $testdata2;
+	my $sumcount2;
+	my $funcdata2;
+	my $checkdata2;
+	my $testfncdata2;
+	my $sumfnccount2;
+	my $testbrdata2;
+	my $sumbrcount2;
+
+	my %result;		# Hash containing combined entry
+	my %result_testdata;
+	my $result_sumcount = {};
+	my $result_funcdata;
+	my $result_testfncdata;
+	my $result_sumfnccount;
+	my $result_testbrdata;
+	my $result_sumbrcount;
+	my $lines_found;
+	my $lines_hit;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+
+	my $testname;
+	my $filename = $_[2];
+
+	# Retrieve data
+	($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
+	 $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
+	($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
+	 $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
+
+	# Merge checksums
+	$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
+
+	# Combine funcdata
+	$result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename);
+
+	# Combine function call count data
+	$result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
+	($result_sumfnccount, $fn_found, $fn_hit) =
+		add_fnccount($sumfnccount1, $sumfnccount2);
+	
+	# Combine branch coverage data
+	$result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
+	($result_sumbrcount, $br_found, $br_hit) =
+		combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
+
+	# Combine testdata
+	foreach $testname (keys(%{$testdata1}))
+	{
+		if (defined($testdata2->{$testname}))
+		{
+			# testname is present in both entries, requires
+			# combination
+			($result_testdata{$testname}) =
+				add_counts($testdata1->{$testname},
+					   $testdata2->{$testname});
+		}
+		else
+		{
+			# testname only present in entry1, add to result
+			$result_testdata{$testname} = $testdata1->{$testname};
+		}
+
+		# update sum count hash
+		($result_sumcount, $lines_found, $lines_hit) =
+			add_counts($result_sumcount,
+				   $result_testdata{$testname});
+	}
+
+	foreach $testname (keys(%{$testdata2}))
+	{
+		# Skip testnames already covered by previous iteration
+		if (defined($testdata1->{$testname})) { next; }
+
+		# testname only present in entry2, add to result hash
+		$result_testdata{$testname} = $testdata2->{$testname};
+
+		# update sum count hash
+		($result_sumcount, $lines_found, $lines_hit) =
+			add_counts($result_sumcount,
+				   $result_testdata{$testname});
+	}
+	
+	# Calculate resulting sumcount
+
+	# Store result
+	set_info_entry(\%result, \%result_testdata, $result_sumcount,
+		       $result_funcdata, $checkdata1, $result_testfncdata,
+		       $result_sumfnccount, $result_testbrdata,
+		       $result_sumbrcount, $lines_found, $lines_hit,
+		       $fn_found, $fn_hit, $br_found, $br_hit);
+
+	return(\%result);
+}
+
+
+#
+# combine_info_files(info_ref1, info_ref2)
+#
+# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
+# reference to resulting hash.
+#
+
+sub combine_info_files($$)
+{
+	my %hash1 = %{$_[0]};
+	my %hash2 = %{$_[1]};
+	my $filename;
+
+	foreach $filename (keys(%hash2))
+	{
+		if ($hash1{$filename})
+		{
+			# Entry already exists in hash1, combine them
+			$hash1{$filename} =
+				combine_info_entries($hash1{$filename},
+						     $hash2{$filename},
+						     $filename);
+		}
+		else
+		{
+			# Entry is unique in both hashes, simply add to
+			# resulting hash
+			$hash1{$filename} = $hash2{$filename};
+		}
+	}
+
+	return(\%hash1);
+}
+
+
+#
+# get_prefix(min_dir, filename_list)
+#
+# Search FILENAME_LIST for a directory prefix which is common to as many
+# list entries as possible, so that removing this prefix will minimize the
+# sum of the lengths of all resulting shortened filenames while observing
+# that no filename has less than MIN_DIR parent directories.
+#
+
+sub get_prefix($@)
+{
+	my ($min_dir, @filename_list) = @_;
+	my %prefix;			# mapping: prefix -> sum of lengths
+	my $current;			# Temporary iteration variable
+
+	# Find list of prefixes
+	foreach (@filename_list)
+	{
+		# Need explicit assignment to get a copy of $_ so that
+		# shortening the contained prefix does not affect the list
+		$current = $_;
+		while ($current = shorten_prefix($current))
+		{
+			$current .= "/";
+
+			# Skip rest if the remaining prefix has already been
+			# added to hash
+			if (exists($prefix{$current})) { last; }
+
+			# Initialize with 0
+			$prefix{$current}="0";
+		}
+
+	}
+
+	# Remove all prefixes that would cause filenames to have less than
+	# the minimum number of parent directories
+	foreach my $filename (@filename_list) {
+		my $dir = dirname($filename);
+
+		for (my $i = 0; $i < $min_dir; $i++) {
+			delete($prefix{$dir."/"});
+			$dir = shorten_prefix($dir);
+		}
+	}
+
+	# Check if any prefix remains
+	return undef if (!%prefix);
+
+	# Calculate sum of lengths for all prefixes
+	foreach $current (keys(%prefix))
+	{
+		foreach (@filename_list)
+		{
+			# Add original length
+			$prefix{$current} += length($_);
+
+			# Check whether prefix matches
+			if (substr($_, 0, length($current)) eq $current)
+			{
+				# Subtract prefix length for this filename
+				$prefix{$current} -= length($current);
+			}
+		}
+	}
+
+	# Find and return prefix with minimal sum
+	$current = (keys(%prefix))[0];
+
+	foreach (keys(%prefix))
+	{
+		if ($prefix{$_} < $prefix{$current})
+		{
+			$current = $_;
+		}
+	}
+
+	$current =~ s/\/$//;
+
+	return($current);
+}
+
+
+#
+# shorten_prefix(prefix)
+#
+# Return PREFIX shortened by last directory component.
+#
+
+sub shorten_prefix($)
+{
+	my @list = split("/", $_[0]);
+
+	pop(@list);
+	return join("/", @list);
+}
+
+
+
+#
+# get_dir_list(filename_list)
+#
+# Return sorted list of directories for each entry in given FILENAME_LIST.
+#
+
+sub get_dir_list(@)
+{
+	my %result;
+
+	foreach (@_)
+	{
+		$result{shorten_prefix($_)} = "";
+	}
+
+	return(sort(keys(%result)));
+}
+
+
+#
+# get_relative_base_path(subdirectory)
+#
+# Return a relative path string which references the base path when applied
+# in SUBDIRECTORY.
+#
+# Example: get_relative_base_path("fs/mm") -> "../../"
+#
+
+sub get_relative_base_path($)
+{
+	my $result = "";
+	my $index;
+
+	# Make an empty directory path a special case
+	if (!$_[0]) { return(""); }
+
+	# Count number of /s in path
+	$index = ($_[0] =~ s/\//\//g);
+
+	# Add a ../ to $result for each / in the directory path + 1
+	for (; $index>=0; $index--)
+	{
+		$result .= "../";
+	}
+
+	return $result;
+}
+
+
+#
+# read_testfile(test_filename)
+#
+# Read in file TEST_FILENAME which contains test descriptions in the format:
+#
+#   TN:<whitespace><test name>
+#   TD:<whitespace><test description>
+#
+# for each test case. Return a reference to a hash containing a mapping
+#
+#   test name -> test description.
+#
+# Die on error.
+#
+
+sub read_testfile($)
+{
+	my %result;
+	my $test_name;
+	my $changed_testname;
+	local *TEST_HANDLE;
+
+	open(TEST_HANDLE, "<", $_[0])
+		or die("ERROR: cannot open $_[0]!\n");
+
+	while (<TEST_HANDLE>)
+	{
+		chomp($_);
+
+		# Match lines beginning with TN:<whitespace(s)>
+		if (/^TN:\s+(.*?)\s*$/)
+		{
+			# Store name for later use
+			$test_name = $1;
+			if ($test_name =~ s/\W/_/g)
+			{
+				$changed_testname = 1;
+			}
+		}
+
+		# Match lines beginning with TD:<whitespace(s)>
+		if (/^TD:\s+(.*?)\s*$/)
+		{
+			if (!defined($test_name)) {
+				die("ERROR: Found test description without prior test name in $_[0]:$.\n");
+			}
+			# Check for empty line
+			if ($1)
+			{
+				# Add description to hash
+				$result{$test_name} .= " $1";
+			}
+			else
+			{
+				# Add empty line
+				$result{$test_name} .= "\n\n";
+			}
+		}
+	}
+
+	close(TEST_HANDLE);
+
+	if ($changed_testname)
+	{
+		warn("WARNING: invalid characters removed from testname in ".
+		     "descriptions file $_[0]\n");
+	}
+
+	return \%result;
+}
+
+
+#
+# escape_html(STRING)
+#
+# Return a copy of STRING in which all occurrences of HTML special characters
+# are escaped.
+#
+
+sub escape_html($)
+{
+	my $string = $_[0];
+
+	if (!$string) { return ""; }
+
+	$string =~ s/&/&amp;/g;		# & -> &amp;
+	$string =~ s/</&lt;/g;		# < -> &lt;
+	$string =~ s/>/&gt;/g;		# > -> &gt;
+	$string =~ s/\"/&quot;/g;	# " -> &quot;
+
+	while ($string =~ /^([^\t]*)(\t)/)
+	{
+		my $replacement = " "x($tab_size - (length($1) % $tab_size));
+		$string =~ s/^([^\t]*)(\t)/$1$replacement/;
+	}
+
+	$string =~ s/\n/<br>/g;		# \n -> <br>
+
+	return $string;
+}
+
+
+#
+# get_date_string()
+#
+# Return the current date in the form: yyyy-mm-dd
+#
+
+sub get_date_string()
+{
+	my $year;
+	my $month;
+	my $day;
+	my $hour;
+	my $min;
+	my $sec;
+	my @timeresult;
+
+	if (defined $ENV{'SOURCE_DATE_EPOCH'})
+	{
+		@timeresult = gmtime($ENV{'SOURCE_DATE_EPOCH'});
+	}
+	else
+	{
+		@timeresult = localtime();
+	}
+	($year, $month, $day, $hour, $min, $sec) =
+		@timeresult[5, 4, 3, 2, 1, 0];
+
+	return sprintf("%d-%02d-%02d %02d:%02d:%02d", $year+1900, $month+1,
+		       $day, $hour, $min, $sec);
+}
+
+
+#
+# create_sub_dir(dir_name)
+#
+# Create subdirectory DIR_NAME if it does not already exist, including all its
+# parent directories.
+#
+# Die on error.
+#
+
+sub create_sub_dir($)
+{
+	my ($dir) = @_;
+
+	system("mkdir", "-p" ,$dir)
+		and die("ERROR: cannot create directory $dir!\n");
+}
+
+
+#
+# write_description_file(descriptions, overall_found, overall_hit,
+#                        total_fn_found, total_fn_hit, total_br_found,
+#                        total_br_hit)
+#
+# Write HTML file containing all test case descriptions. DESCRIPTIONS is a
+# reference to a hash containing a mapping
+#
+#   test case name -> test case description
+#
+# Die on error.
+#
+
+sub write_description_file($$$$$$$)
+{
+	my %description = %{$_[0]};
+	my $found = $_[1];
+	my $hit = $_[2];
+	my $fn_found = $_[3];
+	my $fn_hit = $_[4];
+	my $br_found = $_[5];
+	my $br_hit = $_[6];
+	my $test_name;
+	local *HTML_HANDLE;
+
+	html_create(*HTML_HANDLE,"descriptions.$html_ext");
+	write_html_prolog(*HTML_HANDLE, "", "LCOV - test case descriptions");
+	write_header(*HTML_HANDLE, 3, "", "", $found, $hit, $fn_found,
+		     $fn_hit, $br_found, $br_hit, 0);
+
+	write_test_table_prolog(*HTML_HANDLE,
+			 "Test case descriptions - alphabetical list");
+
+	foreach $test_name (sort(keys(%description)))
+	{
+		my $desc = $description{$test_name};
+
+		$desc = escape_html($desc) if (!$rc_desc_html);
+		write_test_table_entry(*HTML_HANDLE, $test_name, $desc);
+	}
+
+	write_test_table_epilog(*HTML_HANDLE);
+	write_html_epilog(*HTML_HANDLE, "");
+
+	close(*HTML_HANDLE);
+}
+
+
+
+#
+# write_png_files()
+#
+# Create all necessary .png files for the HTML-output in the current
+# directory. .png-files are used as bar graphs.
+#
+# Die on error.
+#
+
+sub write_png_files()
+{
+	my %data;
+	local *PNG_HANDLE;
+
+	$data{"ruby.png"} =
+		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
+		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
+		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
+		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x18, 0x10, 0x5d, 0x57, 
+		 0x34, 0x6e, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
+		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
+		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
+		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
+		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x35, 0x2f, 
+		 0x00, 0x00, 0x00, 0xd0, 0x33, 0x9a, 0x9d, 0x00, 0x00, 0x00, 
+		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
+		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
+		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
+		 0x82];
+	$data{"amber.png"} =
+		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
+		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
+		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
+		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x28, 0x04, 0x98, 0xcb, 
+		 0xd6, 0xe0, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
+		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
+		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
+		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
+		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xe0, 0x50, 
+		 0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00, 0x00, 0x00, 
+		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
+	  	 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
+		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
+		 0x82];
+	$data{"emerald.png"} =
+		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
+		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
+		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
+		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x22, 0x2b, 0xc9, 0xf5, 
+		 0x03, 0x33, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
+		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
+		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
+		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
+		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0xea, 0x59, 
+		 0x0a, 0x0a, 0x0a, 0x0f, 0xba, 0x50, 0x83, 0x00, 0x00, 0x00, 
+		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
+		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
+		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
+		 0x82];
+	$data{"snow.png"} =
+		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
+		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
+		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
+		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x1e, 0x1d, 0x75, 0xbc, 
+		 0xef, 0x55, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
+		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
+		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
+		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
+		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 
+		 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 
+		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
+		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
+		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
+		 0x82];
+	$data{"glass.png"} =
+		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
+		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
+		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
+		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
+		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 
+		 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 
+		 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 
+		 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, 
+		 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 
+		 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 
+		 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 
+		 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x13, 0x0f, 0x08, 0x19, 0xc4, 
+		 0x40, 0x56, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 
+		 0x54, 0x78, 0x9c, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 
+		 0x01, 0x48, 0xaf, 0xa4, 0x71, 0x00, 0x00, 0x00, 0x00, 0x49, 
+		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
+	$data{"updown.png"} =
+		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a, 
+		 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x16, 
+		 0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00, 0x3c, 0x49, 0x44, 0x41, 
+		 0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x03, 0xff, 0xa1, 0x00, 
+		 0x5d, 0x9c, 0x11, 0x5d, 0x11, 0x8a, 0x24, 0x23, 0x23, 0x23, 
+		 0x86, 0x42, 0x6c, 0xa6, 0x20, 0x2b, 0x66, 0xc4, 0xa7, 0x08, 
+		 0x59, 0x31, 0x23, 0x21, 0x45, 0x30, 0xc0, 0xc4, 0x30, 0x60, 
+		 0x80, 0xfa, 0x6e, 0x24, 0x3e, 0x78, 0x48, 0x0a, 0x70, 0x62, 
+		 0xa2, 0x90, 0x81, 0xd8, 0x44, 0x01, 0x00, 0xe9, 0x5c, 0x2f, 
+		 0xf5, 0xe2, 0x9d, 0x0f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x49, 
+		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort);
+	foreach (keys(%data))
+	{
+		open(PNG_HANDLE, ">", $_)
+			or die("ERROR: cannot create $_!\n");
+		binmode(PNG_HANDLE);
+		print(PNG_HANDLE map(chr,@{$data{$_}}));
+		close(PNG_HANDLE);
+	}
+}
+
+
+#
+# write_htaccess_file()
+#
+
+sub write_htaccess_file()
+{
+	local *HTACCESS_HANDLE;
+	my $htaccess_data;
+
+	open(*HTACCESS_HANDLE, ">", ".htaccess")
+		or die("ERROR: cannot open .htaccess for writing!\n");
+
+	$htaccess_data = (<<"END_OF_HTACCESS")
+AddEncoding x-gzip .html
+END_OF_HTACCESS
+	;
+
+	print(HTACCESS_HANDLE $htaccess_data);
+	close(*HTACCESS_HANDLE);
+}
+
+
+#
+# write_css_file()
+#
+# Write the cascading style sheet file gcov.css to the current directory.
+# This file defines basic layout attributes of all generated HTML pages.
+#
+
+sub write_css_file()
+{
+	local *CSS_HANDLE;
+
+	# Check for a specified external style sheet file
+	if ($css_filename)
+	{
+		# Simply copy that file
+		system("cp", $css_filename, "gcov.css")
+			and die("ERROR: cannot copy file $css_filename!\n");
+		return;
+	}
+
+	open(CSS_HANDLE, ">", "gcov.css")
+		or die ("ERROR: cannot open gcov.css for writing!\n");
+
+
+	# *************************************************************
+
+	my $css_data = ($_=<<"END_OF_CSS")
+	/* All views: initial background and text color */
+	body
+	{
+	  color: #000000;
+	  background-color: #FFFFFF;
+	}
+	
+	/* All views: standard link format*/
+	a:link
+	{
+	  color: #284FA8;
+	  text-decoration: underline;
+	}
+	
+	/* All views: standard link - visited format */
+	a:visited
+	{
+	  color: #00CB40;
+	  text-decoration: underline;
+	}
+	
+	/* All views: standard link - activated format */
+	a:active
+	{
+	  color: #FF0040;
+	  text-decoration: underline;
+	}
+	
+	/* All views: main title format */
+	td.title
+	{
+	  text-align: center;
+	  padding-bottom: 10px;
+	  font-family: sans-serif;
+	  font-size: 20pt;
+	  font-style: italic;
+	  font-weight: bold;
+	}
+	
+	/* All views: header item format */
+	td.headerItem
+	{
+	  text-align: right;
+	  padding-right: 6px;
+	  font-family: sans-serif;
+	  font-weight: bold;
+	  vertical-align: top;
+	  white-space: nowrap;
+	}
+	
+	/* All views: header item value format */
+	td.headerValue
+	{
+	  text-align: left;
+	  color: #284FA8;
+	  font-family: sans-serif;
+	  font-weight: bold;
+	  white-space: nowrap;
+	}
+
+	/* All views: header item coverage table heading */
+	td.headerCovTableHead
+	{
+	  text-align: center;
+	  padding-right: 6px;
+	  padding-left: 6px;
+	  padding-bottom: 0px;
+	  font-family: sans-serif;
+	  font-size: 80%;
+	  white-space: nowrap;
+	}
+	
+	/* All views: header item coverage table entry */
+	td.headerCovTableEntry
+	{
+	  text-align: right;
+	  color: #284FA8;
+	  font-family: sans-serif;
+	  font-weight: bold;
+	  white-space: nowrap;
+	  padding-left: 12px;
+	  padding-right: 4px;
+	  background-color: #DAE7FE;
+	}
+	
+	/* All views: header item coverage table entry for high coverage rate */
+	td.headerCovTableEntryHi
+	{
+	  text-align: right;
+	  color: #000000;
+	  font-family: sans-serif;
+	  font-weight: bold;
+	  white-space: nowrap;
+	  padding-left: 12px;
+	  padding-right: 4px;
+	  background-color: #A7FC9D;
+	}
+	
+	/* All views: header item coverage table entry for medium coverage rate */
+	td.headerCovTableEntryMed
+	{
+	  text-align: right;
+	  color: #000000;
+	  font-family: sans-serif;
+	  font-weight: bold;
+	  white-space: nowrap;
+	  padding-left: 12px;
+	  padding-right: 4px;
+	  background-color: #FFEA20;
+	}
+	
+	/* All views: header item coverage table entry for ow coverage rate */
+	td.headerCovTableEntryLo
+	{
+	  text-align: right;
+	  color: #000000;
+	  font-family: sans-serif;
+	  font-weight: bold;
+	  white-space: nowrap;
+	  padding-left: 12px;
+	  padding-right: 4px;
+	  background-color: #FF0000;
+	}
+	
+	/* All views: header legend value for legend entry */
+	td.headerValueLeg
+	{
+	  text-align: left;
+	  color: #000000;
+	  font-family: sans-serif;
+	  font-size: 80%;
+	  white-space: nowrap;
+	  padding-top: 4px;
+	}
+	
+	/* All views: color of horizontal ruler */
+	td.ruler
+	{
+	  background-color: #6688D4;
+	}
+	
+	/* All views: version string format */
+	td.versionInfo
+	{
+	  text-align: center;
+	  padding-top: 2px;
+	  font-family: sans-serif;
+	  font-style: italic;
+	}
+	
+	/* Directory view/File view (all)/Test case descriptions:
+	   table headline format */
+	td.tableHead
+	{
+	  text-align: center;
+	  color: #FFFFFF;
+	  background-color: #6688D4;
+	  font-family: sans-serif;
+	  font-size: 120%;
+	  font-weight: bold;
+	  white-space: nowrap;
+	  padding-left: 4px;
+	  padding-right: 4px;
+	}
+
+	span.tableHeadSort
+	{
+	  padding-right: 4px;
+	}
+	
+	/* Directory view/File view (all): filename entry format */
+	td.coverFile
+	{
+	  text-align: left;
+	  padding-left: 10px;
+	  padding-right: 20px; 
+	  color: #284FA8;
+	  background-color: #DAE7FE;
+	  font-family: monospace;
+	}
+	
+	/* Directory view/File view (all): bar-graph entry format*/
+	td.coverBar
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #DAE7FE;
+	}
+	
+	/* Directory view/File view (all): bar-graph outline color */
+	td.coverBarOutline
+	{
+	  background-color: #000000;
+	}
+	
+	/* Directory view/File view (all): percentage entry for files with
+	   high coverage rate */
+	td.coverPerHi
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #A7FC9D;
+	  font-weight: bold;
+	  font-family: sans-serif;
+	}
+	
+	/* Directory view/File view (all): line count entry for files with
+	   high coverage rate */
+	td.coverNumHi
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #A7FC9D;
+	  white-space: nowrap;
+	  font-family: sans-serif;
+	}
+	
+	/* Directory view/File view (all): percentage entry for files with
+	   medium coverage rate */
+	td.coverPerMed
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #FFEA20;
+	  font-weight: bold;
+	  font-family: sans-serif;
+	}
+	
+	/* Directory view/File view (all): line count entry for files with
+	   medium coverage rate */
+	td.coverNumMed
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #FFEA20;
+	  white-space: nowrap;
+	  font-family: sans-serif;
+	}
+	
+	/* Directory view/File view (all): percentage entry for files with
+	   low coverage rate */
+	td.coverPerLo
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #FF0000;
+	  font-weight: bold;
+	  font-family: sans-serif;
+	}
+	
+	/* Directory view/File view (all): line count entry for files with
+	   low coverage rate */
+	td.coverNumLo
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #FF0000;
+	  white-space: nowrap;
+	  font-family: sans-serif;
+	}
+	
+	/* File view (all): "show/hide details" link format */
+	a.detail:link
+	{
+	  color: #B8D0FF;
+	  font-size:80%;
+	}
+	
+	/* File view (all): "show/hide details" link - visited format */
+	a.detail:visited
+	{
+	  color: #B8D0FF;
+	  font-size:80%;
+	}
+	
+	/* File view (all): "show/hide details" link - activated format */
+	a.detail:active
+	{
+	  color: #FFFFFF;
+	  font-size:80%;
+	}
+	
+	/* File view (detail): test name entry */
+	td.testName
+	{
+	  text-align: right;
+	  padding-right: 10px;
+	  background-color: #DAE7FE;
+	  font-family: sans-serif;
+	}
+	
+	/* File view (detail): test percentage entry */
+	td.testPer
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px; 
+	  background-color: #DAE7FE;
+	  font-family: sans-serif;
+	}
+	
+	/* File view (detail): test lines count entry */
+	td.testNum
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px; 
+	  background-color: #DAE7FE;
+	  font-family: sans-serif;
+	}
+	
+	/* Test case descriptions: test name format*/
+	dt
+	{
+	  font-family: sans-serif;
+	  font-weight: bold;
+	}
+	
+	/* Test case descriptions: description table body */
+	td.testDescription
+	{
+	  padding-top: 10px;
+	  padding-left: 30px;
+	  padding-bottom: 10px;
+	  padding-right: 30px;
+	  background-color: #DAE7FE;
+	}
+	
+	/* Source code view: function entry */
+	td.coverFn
+	{
+	  text-align: left;
+	  padding-left: 10px;
+	  padding-right: 20px; 
+	  color: #284FA8;
+	  background-color: #DAE7FE;
+	  font-family: monospace;
+	}
+
+	/* Source code view: function entry zero count*/
+	td.coverFnLo
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #FF0000;
+	  font-weight: bold;
+	  font-family: sans-serif;
+	}
+
+	/* Source code view: function entry nonzero count*/
+	td.coverFnHi
+	{
+	  text-align: right;
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  background-color: #DAE7FE;
+	  font-weight: bold;
+	  font-family: sans-serif;
+	}
+
+	/* Source code view: source code format */
+	pre.source
+	{
+	  font-family: monospace;
+	  white-space: pre;
+	  margin-top: 2px;
+	}
+	
+	/* Source code view: line number format */
+	span.lineNum
+	{
+	  background-color: #EFE383;
+	}
+	
+	/* Source code view: format for lines which were executed */
+	td.lineCov,
+	span.lineCov
+	{
+	  background-color: #CAD7FE;
+	}
+	
+	/* Source code view: format for Cov legend */
+	span.coverLegendCov
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-bottom: 2px;
+	  background-color: #CAD7FE;
+	}
+	
+	/* Source code view: format for lines which were not executed */
+	td.lineNoCov,
+	span.lineNoCov
+	{
+	  background-color: #FF6230;
+	}
+	
+	/* Source code view: format for NoCov legend */
+	span.coverLegendNoCov
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-bottom: 2px;
+	  background-color: #FF6230;
+	}
+	
+	/* Source code view (function table): standard link - visited format */
+	td.lineNoCov > a:visited,
+	td.lineCov > a:visited
+	{  
+	  color: black;
+	  text-decoration: underline;
+	}  
+	
+	/* Source code view: format for lines which were executed only in a
+	   previous version */
+	span.lineDiffCov
+	{
+	  background-color: #B5F7AF;
+	}
+	
+	/* Source code view: format for branches which were executed
+	 * and taken */
+	span.branchCov
+	{
+	  background-color: #CAD7FE;
+	}
+
+	/* Source code view: format for branches which were executed
+	 * but not taken */
+	span.branchNoCov
+	{
+	  background-color: #FF6230;
+	}
+
+	/* Source code view: format for branches which were not executed */
+	span.branchNoExec
+	{
+	  background-color: #FF6230;
+	}
+
+	/* Source code view: format for the source code heading line */
+	pre.sourceHeading
+	{
+	  white-space: pre;
+	  font-family: monospace;
+	  font-weight: bold;
+	  margin: 0px;
+	}
+
+	/* All views: header legend value for low rate */
+	td.headerValueLegL
+	{
+	  font-family: sans-serif;
+	  text-align: center;
+	  white-space: nowrap;
+	  padding-left: 4px;
+	  padding-right: 2px;
+	  background-color: #FF0000;
+	  font-size: 80%;
+	}
+
+	/* All views: header legend value for med rate */
+	td.headerValueLegM
+	{
+	  font-family: sans-serif;
+	  text-align: center;
+	  white-space: nowrap;
+	  padding-left: 2px;
+	  padding-right: 2px;
+	  background-color: #FFEA20;
+	  font-size: 80%;
+	}
+
+	/* All views: header legend value for hi rate */
+	td.headerValueLegH
+	{
+	  font-family: sans-serif;
+	  text-align: center;
+	  white-space: nowrap;
+	  padding-left: 2px;
+	  padding-right: 4px;
+	  background-color: #A7FC9D;
+	  font-size: 80%;
+	}
+
+	/* All views except source code view: legend format for low coverage */
+	span.coverLegendCovLo
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-top: 2px;
+	  background-color: #FF0000;
+	}
+
+	/* All views except source code view: legend format for med coverage */
+	span.coverLegendCovMed
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-top: 2px;
+	  background-color: #FFEA20;
+	}
+
+	/* All views except source code view: legend format for hi coverage */
+	span.coverLegendCovHi
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-top: 2px;
+	  background-color: #A7FC9D;
+	}
+END_OF_CSS
+	;
+
+	# *************************************************************
+
+
+	# Remove leading tab from all lines
+	$css_data =~ s/^\t//gm;
+
+	print(CSS_HANDLE $css_data);
+
+	close(CSS_HANDLE);
+}
+
+
+#
+# get_bar_graph_code(base_dir, cover_found, cover_hit)
+#
+# Return a string containing HTML code which implements a bar graph display
+# for a coverage rate of cover_hit * 100 / cover_found.
+#
+
+sub get_bar_graph_code($$$)
+{
+	my ($base_dir, $found, $hit) = @_;
+	my $rate;
+	my $alt;
+	my $width;
+	my $remainder;
+	my $png_name;
+	my $graph_code;
+
+	# Check number of instrumented lines
+	if ($_[1] == 0) { return ""; }
+
+	$alt		= rate($hit, $found, "%");
+	$width		= rate($hit, $found, undef, 0);
+	$remainder	= 100 - $width;
+
+	# Decide which .png file to use
+	$png_name = $rate_png[classify_rate($found, $hit, $med_limit,
+					    $hi_limit)];
+
+	if ($width == 0)
+	{
+		# Zero coverage
+		$graph_code = (<<END_OF_HTML)
+	        <table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="$_[0]snow.png" width=100 height=10 alt="$alt"></td></tr></table>
+END_OF_HTML
+		;
+	}
+	elsif ($width == 100)
+	{
+		# Full coverage
+		$graph_code = (<<END_OF_HTML)
+		<table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="$_[0]$png_name" width=100 height=10 alt="$alt"></td></tr></table>
+END_OF_HTML
+		;
+	}
+	else
+	{
+		# Positive coverage
+		$graph_code = (<<END_OF_HTML)
+		<table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="$_[0]$png_name" width=$width height=10 alt="$alt"><img src="$_[0]snow.png" width=$remainder height=10 alt="$alt"></td></tr></table>
+END_OF_HTML
+		;
+	}
+
+	# Remove leading tabs from all lines
+	$graph_code =~ s/^\t+//gm;
+	chomp($graph_code);
+
+	return($graph_code);
+}
+
+#
+# sub classify_rate(found, hit, med_limit, high_limit)
+#
+# Return 0 for low rate, 1 for medium rate and 2 for hi rate.
+#
+
+sub classify_rate($$$$)
+{
+	my ($found, $hit, $med, $hi) = @_;
+	my $rate;
+
+	if ($found == 0) {
+		return 2;
+	}
+	$rate = rate($hit, $found);
+	if ($rate < $med) {
+		return 0;
+	} elsif ($rate < $hi) {
+		return 1;
+	}
+	return 2;
+}
+
+
+#
+# write_html(filehandle, html_code)
+#
+# Write out HTML_CODE to FILEHANDLE while removing a leading tabulator mark
+# in each line of HTML_CODE.
+#
+
+sub write_html(*$)
+{
+	local *HTML_HANDLE = $_[0];
+	my $html_code = $_[1];
+
+	# Remove leading tab from all lines
+	$html_code =~ s/^\t//gm;
+
+	print(HTML_HANDLE $html_code)
+		or die("ERROR: cannot write HTML data ($!)\n");
+}
+
+
+#
+# write_html_prolog(filehandle, base_dir, pagetitle)
+#
+# Write an HTML prolog common to all HTML files to FILEHANDLE. PAGETITLE will
+# be used as HTML page title. BASE_DIR contains a relative path which points
+# to the base directory.
+#
+
+sub write_html_prolog(*$$)
+{
+	my $basedir = $_[1];
+	my $pagetitle = $_[2];
+	my $prolog;
+
+	$prolog = $html_prolog;
+	$prolog =~ s/\@pagetitle\@/$pagetitle/g;
+	$prolog =~ s/\@basedir\@/$basedir/g;
+
+	write_html($_[0], $prolog);
+}
+
+
+#
+# write_header_prolog(filehandle, base_dir)
+#
+# Write beginning of page header HTML code.
+#
+
+sub write_header_prolog(*$)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	  <table width="100%" border=0 cellspacing=0 cellpadding=0>
+	    <tr><td class="title">$title</td></tr>
+	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+
+	    <tr>
+	      <td width="100%">
+	        <table cellpadding=1 border=0 width="100%">
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_header_line(handle, content)
+#
+# Write a header line with the specified table contents.
+#
+
+sub write_header_line(*@)
+{
+	my ($handle, @content) = @_;
+	my $entry;
+
+	write_html($handle, "          <tr>\n");
+	foreach $entry (@content) {
+		my ($width, $class, $text, $colspan) = @{$entry};
+
+		if (defined($width)) {
+			$width = " width=\"$width\"";
+		} else {
+			$width = "";
+		}
+		if (defined($class)) {
+			$class = " class=\"$class\"";
+		} else {
+			$class = "";
+		}
+		if (defined($colspan)) {
+			$colspan = " colspan=\"$colspan\"";
+		} else {
+			$colspan = "";
+		}
+		$text = "" if (!defined($text));
+		write_html($handle,
+			   "            <td$width$class$colspan>$text</td>\n");
+	}
+	write_html($handle, "          </tr>\n");
+}
+
+
+#
+# write_header_epilog(filehandle, base_dir)
+#
+# Write end of page header HTML code.
+#
+
+sub write_header_epilog(*$)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	          <tr><td><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+	        </table>
+	      </td>
+	    </tr>
+
+	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+	  </table>
+
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_file_table_prolog(handle, file_heading, ([heading, num_cols], ...))
+#
+# Write heading for file table.
+#
+
+sub write_file_table_prolog(*$@)
+{
+	my ($handle, $file_heading, @columns) = @_;
+	my $num_columns = 0;
+	my $file_width;
+	my $col;
+	my $width;
+
+	$width = 20 if (scalar(@columns) == 1);
+	$width = 10 if (scalar(@columns) == 2);
+	$width = 8 if (scalar(@columns) > 2);
+
+	foreach $col (@columns) {
+		my ($heading, $cols) = @{$col};
+
+		$num_columns += $cols;
+	}
+	$file_width = 100 - $num_columns * $width;
+
+	# Table definition
+	write_html($handle, <<END_OF_HTML);
+	  <center>
+	  <table width="80%" cellpadding=1 cellspacing=1 border=0>
+
+	    <tr>
+	      <td width="$file_width%"><br></td>
+END_OF_HTML
+	# Empty first row
+	foreach $col (@columns) {
+		my ($heading, $cols) = @{$col};
+
+		while ($cols-- > 0) {
+			write_html($handle, <<END_OF_HTML);
+	      <td width="$width%"></td>
+END_OF_HTML
+		}
+	}
+	# Next row
+	write_html($handle, <<END_OF_HTML);
+	    </tr>
+
+	    <tr>
+	      <td class="tableHead">$file_heading</td>
+END_OF_HTML
+	# Heading row
+	foreach $col (@columns) {
+		my ($heading, $cols) = @{$col};
+		my $colspan = "";
+
+		$colspan = " colspan=$cols" if ($cols > 1);
+		write_html($handle, <<END_OF_HTML);
+	      <td class="tableHead"$colspan>$heading</td>
+END_OF_HTML
+	}
+	write_html($handle, <<END_OF_HTML);
+	    </tr>
+END_OF_HTML
+}
+
+
+# write_file_table_entry(handle, base_dir, filename, page_link,
+#			 ([ found, hit, med_limit, hi_limit, graph ], ..)
+#
+# Write an entry of the file table.
+#
+
+sub write_file_table_entry(*$$$@)
+{
+	my ($handle, $base_dir, $filename, $page_link, @entries) = @_;
+	my $file_code;
+	my $entry;
+	my $esc_filename = escape_html($filename);
+
+	# Add link to source if provided
+	if (defined($page_link) && $page_link ne "") {
+		$file_code = "<a href=\"$page_link\">$esc_filename</a>";
+	} else {
+		$file_code = $esc_filename;
+	}
+
+	# First column: filename
+	write_html($handle, <<END_OF_HTML);
+	    <tr>
+	      <td class="coverFile">$file_code</td>
+END_OF_HTML
+	# Columns as defined
+	foreach $entry (@entries) {
+		my ($found, $hit, $med, $hi, $graph) = @{$entry};
+		my $bar_graph;
+		my $class;
+		my $rate;
+
+		# Generate bar graph if requested
+		if ($graph) {
+			$bar_graph = get_bar_graph_code($base_dir, $found,
+							$hit);
+			write_html($handle, <<END_OF_HTML);
+	      <td class="coverBar" align="center">
+	        $bar_graph
+	      </td>
+END_OF_HTML
+		}
+		# Get rate color and text
+		if ($found == 0) {
+			$rate = "-";
+			$class = "Hi";
+		} else {
+			$rate = rate($hit, $found, "&nbsp;%");
+			$class = $rate_name[classify_rate($found, $hit,
+					    $med, $hi)];
+		}
+		if ($opt_missed) {
+			# Show negative number of items without coverage
+			$hit = -($found - $hit);
+		}
+		write_html($handle, <<END_OF_HTML);
+	      <td class="coverPer$class">$rate</td>
+	      <td class="coverNum$class">$hit / $found</td>
+END_OF_HTML
+	}
+	# End of row
+        write_html($handle, <<END_OF_HTML);
+	    </tr>
+END_OF_HTML
+}
+
+
+#
+# write_file_table_detail_entry(filehandle, test_name, ([found, hit], ...))
+#
+# Write entry for detail section in file table.
+#
+
+sub write_file_table_detail_entry(*$@)
+{
+	my ($handle, $test, @entries) = @_;
+	my $entry;
+
+	if ($test eq "") {
+		$test = "<span style=\"font-style:italic\">&lt;unnamed&gt;</span>";
+	} elsif ($test =~ /^(.*),diff$/) {
+		$test = $1." (converted)";
+	}
+	# Testname
+	write_html($handle, <<END_OF_HTML);
+	    <tr>
+	      <td class="testName" colspan=2>$test</td>
+END_OF_HTML
+	# Test data
+	foreach $entry (@entries) {
+		my ($found, $hit) = @{$entry};
+		my $rate = rate($hit, $found, "&nbsp;%");
+
+		write_html($handle, <<END_OF_HTML);
+	      <td class="testPer">$rate</td>
+	      <td class="testNum">$hit&nbsp;/&nbsp;$found</td>
+END_OF_HTML
+	}
+
+        write_html($handle, <<END_OF_HTML);
+	    </tr>
+
+END_OF_HTML
+
+	# *************************************************************
+}
+
+
+#
+# write_file_table_epilog(filehandle)
+#
+# Write end of file table HTML code.
+#
+
+sub write_file_table_epilog(*)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	  </table>
+	  </center>
+	  <br>
+
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_test_table_prolog(filehandle, table_heading)
+#
+# Write heading for test case description table.
+#
+
+sub write_test_table_prolog(*$)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	  <center>
+	  <table width="80%" cellpadding=2 cellspacing=1 border=0>
+
+	    <tr>
+	      <td><br></td>
+	    </tr>
+
+	    <tr>
+	      <td class="tableHead">$_[1]</td>
+	    </tr>
+
+	    <tr>
+	      <td class="testDescription">
+	        <dl>
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_test_table_entry(filehandle, test_name, test_description)
+#
+# Write entry for the test table.
+#
+
+sub write_test_table_entry(*$$)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+          <dt>$_[1]<a name="$_[1]">&nbsp;</a></dt>
+          <dd>$_[2]<br><br></dd>
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_test_table_epilog(filehandle)
+#
+# Write end of test description table HTML code.
+#
+
+sub write_test_table_epilog(*)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	        </dl>
+	      </td>
+	    </tr>
+	  </table>
+	  </center>
+	  <br>
+
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+sub fmt_centered($$)
+{
+	my ($width, $text) = @_;
+	my $w0 = length($text);
+	my $w1 = $width > $w0 ? int(($width - $w0) / 2) : 0;
+	my $w2 = $width > $w0 ? $width - $w0 - $w1 : 0;
+
+	return (" "x$w1).$text.(" "x$w2);
+}
+
+
+#
+# write_source_prolog(filehandle)
+#
+# Write start of source code table.
+#
+
+sub write_source_prolog(*)
+{
+	my $lineno_heading = "         ";
+	my $branch_heading = "";
+	my $line_heading = fmt_centered($line_field_width, "Line data");
+	my $source_heading = " Source code";
+
+	if ($br_coverage) {
+		$branch_heading = fmt_centered($br_field_width, "Branch data").
+				  " ";
+	}
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	  <table cellpadding=0 cellspacing=0 border=0>
+	    <tr>
+	      <td><br></td>
+	    </tr>
+	    <tr>
+	      <td>
+<pre class="sourceHeading">${lineno_heading}${branch_heading}${line_heading} ${source_heading}</pre>
+<pre class="source">
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+sub cmp_blocks($$)
+{
+	my ($a, $b) = @_;
+	my ($fa, $fb) = ($a->[0], $b->[0]);
+
+	return $fa->[0] <=> $fb->[0] if ($fa->[0] != $fb->[0]);
+	return $fa->[1] <=> $fb->[1];
+}
+
+#
+# get_branch_blocks(brdata)
+#
+# Group branches that belong to the same basic block.
+#
+# Returns: [block1, block2, ...]
+# block:   [branch1, branch2, ...]
+# branch:  [block_num, branch_num, taken_count, text_length, open, close]
+#
+
+sub get_branch_blocks($)
+{
+	my ($brdata) = @_;
+	my $last_block_num;
+	my $block = [];
+	my @blocks;
+
+	return () if (!defined($brdata));
+
+	# Group branches
+	foreach my $entry (split(/:/, $brdata)) {
+		my ($block_num, $branch, $taken) = split(/,/, $entry);
+		my $br;
+
+		if (defined($last_block_num) && $block_num != $last_block_num) {
+			push(@blocks, $block);
+			$block = [];
+		}
+		$br = [$block_num, $branch, $taken, 3, 0, 0];
+		push(@{$block}, $br);
+		$last_block_num = $block_num;
+	}
+	push(@blocks, $block) if (scalar(@{$block}) > 0);
+
+	# Add braces to first and last branch in group
+	foreach $block (@blocks) {
+		$block->[0]->[$BR_OPEN] = 1;
+		$block->[0]->[$BR_LEN]++;
+		$block->[scalar(@{$block}) - 1]->[$BR_CLOSE] = 1;
+		$block->[scalar(@{$block}) - 1]->[$BR_LEN]++;
+	}
+
+	return sort(cmp_blocks @blocks);
+}
+
+#
+# get_block_len(block)
+#
+# Calculate total text length of all branches in a block of branches.
+#
+
+sub get_block_len($)
+{
+	my ($block) = @_;
+	my $len = 0;
+	my $branch;
+
+	foreach $branch (@{$block}) {
+		$len += $branch->[$BR_LEN];
+	}
+
+	return $len;
+}
+
+
+#
+# get_branch_html(brdata)
+#
+# Return a list of HTML lines which represent the specified branch coverage
+# data in source code view.
+#
+
+sub get_branch_html($)
+{
+	my ($brdata) = @_;
+	my @blocks = get_branch_blocks($brdata);
+	my $block;
+	my $branch;
+	my $line_len = 0;
+	my $line = [];	# [branch2|" ", branch|" ", ...]
+	my @lines;	# [line1, line2, ...]
+	my @result;
+
+	# Distribute blocks to lines
+	foreach $block (@blocks) {
+		my $block_len = get_block_len($block);
+
+		# Does this block fit into the current line?
+		if ($line_len + $block_len <= $br_field_width) {
+			# Add it
+			$line_len += $block_len;
+			push(@{$line}, @{$block});
+			next;
+		} elsif ($block_len <= $br_field_width) {
+			# It would fit if the line was empty - add it to new
+			# line
+			push(@lines, $line);
+			$line_len = $block_len;
+			$line = [ @{$block} ];
+			next;
+		}
+		# Split the block into several lines
+		foreach $branch (@{$block}) {
+			if ($line_len + $branch->[$BR_LEN] >= $br_field_width) {
+				# Start a new line
+				if (($line_len + 1 <= $br_field_width) &&
+				    scalar(@{$line}) > 0 &&
+				    !$line->[scalar(@$line) - 1]->[$BR_CLOSE]) {
+					# Try to align branch symbols to be in
+					# one # row
+					push(@{$line}, " ");
+				}
+				push(@lines, $line);
+				$line_len = 0;
+				$line = [];
+			}
+			push(@{$line}, $branch);
+			$line_len += $branch->[$BR_LEN];
+		}
+	}
+	push(@lines, $line);
+
+	# Convert to HTML
+	foreach $line (@lines) {
+		my $current = "";
+		my $current_len = 0;
+
+		foreach $branch (@$line) {
+			# Skip alignment space
+			if ($branch eq " ") {
+				$current .= " ";
+				$current_len++;
+				next;
+			}
+
+			my ($block_num, $br_num, $taken, $len, $open, $close) =
+			   @{$branch};
+			my $class;
+			my $title;
+			my $text;
+
+			if ($taken eq '-') {
+				$class	= "branchNoExec";
+				$text	= " # ";
+				$title	= "Branch $br_num was not executed";
+			} elsif ($taken == 0) {
+				$class	= "branchNoCov";
+				$text	= " - ";
+				$title	= "Branch $br_num was not taken";
+			} else {
+				$class	= "branchCov";
+				$text	= " + ";
+				$title	= "Branch $br_num was taken $taken ".
+					  "time";
+				$title .= "s" if ($taken > 1);
+			}
+			$current .= "[" if ($open);
+			$current .= "<span class=\"$class\" title=\"$title\">";
+			$current .= $text."</span>";
+			$current .= "]" if ($close);
+			$current_len += $len;
+		}
+
+		# Right-align result text
+		if ($current_len < $br_field_width) {
+			$current = (" "x($br_field_width - $current_len)).
+				   $current;
+		}
+		push(@result, $current);
+	}
+
+	return @result;
+}
+
+
+#
+# format_count(count, width)
+#
+# Return a right-aligned representation of count that fits in width characters.
+#
+
+sub format_count($$)
+{
+	my ($count, $width) = @_;
+	my $result;
+	my $exp;
+
+	$result = sprintf("%*.0f", $width, $count);
+	while (length($result) > $width) {
+		last if ($count < 10);
+		$exp++;
+		$count = int($count/10);
+		$result = sprintf("%*s", $width, ">$count*10^$exp");
+	}
+	return $result;
+}
+
+#
+# write_source_line(filehandle, line_num, source, hit_count, converted,
+#                   brdata)
+#
+# Write formatted source code line. Return a line in a format as needed
+# by gen_png()
+#
+
+sub write_source_line(*$$$$$)
+{
+	my ($handle, $line, $source, $count, $converted, $brdata) = @_;
+	my $source_format;
+	my $count_format;
+	my $result;
+	my $anchor_start = "";
+	my $anchor_end = "";
+	my $count_field_width = $line_field_width - 1;
+	my @br_html;
+	my $html;
+
+	# Get branch HTML data for this line
+	@br_html = get_branch_html($brdata) if ($br_coverage);
+
+	if (!defined($count)) {
+		$result		= "";
+		$source_format	= "";
+		$count_format	= " "x$count_field_width;
+	}
+	elsif ($count == 0) {
+		$result		= $count;
+		$source_format	= '<span class="lineNoCov">';
+		$count_format	= format_count($count, $count_field_width);
+	}
+	elsif ($converted && defined($highlight)) {
+		$result		= "*".$count;
+		$source_format	= '<span class="lineDiffCov">';
+		$count_format	= format_count($count, $count_field_width);
+	}
+	else {
+		$result		= $count;
+		$source_format	= '<span class="lineCov">';
+		$count_format	= format_count($count, $count_field_width);
+	}
+	$result .= ":".$source;
+
+	# Write out a line number navigation anchor every $nav_resolution
+	# lines if necessary
+	$anchor_start	= "<a name=\"$_[1]\">";
+	$anchor_end	= "</a>";
+
+
+	# *************************************************************
+
+	$html = $anchor_start;
+	$html .= "<span class=\"lineNum\">".sprintf("%8d", $line)." </span>";
+	$html .= shift(@br_html).":" if ($br_coverage);
+	$html .= "$source_format$count_format : ";
+	$html .= escape_html($source);
+	$html .= "</span>" if ($source_format);
+	$html .= $anchor_end."\n";
+
+	write_html($handle, $html);
+
+	if ($br_coverage) {
+		# Add lines for overlong branch information
+		foreach (@br_html) {
+			write_html($handle, "<span class=\"lineNum\">".
+				   "         </span>$_\n");
+		}
+	}
+	# *************************************************************
+
+	return($result);
+}
+
+
+#
+# write_source_epilog(filehandle)
+#
+# Write end of source code table.
+#
+
+sub write_source_epilog(*)
+{
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	</pre>
+	      </td>
+	    </tr>
+	  </table>
+	  <br>
+
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_html_epilog(filehandle, base_dir[, break_frames])
+#
+# Write HTML page footer to FILEHANDLE. BREAK_FRAMES should be set when
+# this page is embedded in a frameset, clicking the URL link will then
+# break this frameset.
+#
+
+sub write_html_epilog(*$;$)
+{
+	my $basedir = $_[1];
+	my $break_code = "";
+	my $epilog;
+
+	if (defined($_[2]))
+	{
+		$break_code = " target=\"_parent\"";
+	}
+
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	  <table width="100%" border=0 cellspacing=0 cellpadding=0>
+	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+	    <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
+	  </table>
+	  <br>
+END_OF_HTML
+	;
+
+	$epilog = $html_epilog;
+	$epilog =~ s/\@basedir\@/$basedir/g;
+
+	write_html($_[0], $epilog);
+}
+
+
+#
+# write_frameset(filehandle, basedir, basename, pagetitle)
+#
+#
+
+sub write_frameset(*$$$)
+{
+	my $frame_width = $overview_width + 40;
+
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">
+
+	<html lang="en">
+
+	<head>
+	  <meta http-equiv="Content-Type" content="text/html; charset=$charset">
+	  <title>$_[3]</title>
+	  <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
+	</head>
+
+	<frameset cols="$frame_width,*">
+	  <frame src="$_[2].gcov.overview.$html_ext" name="overview">
+	  <frame src="$_[2].gcov.$html_ext" name="source">
+	  <noframes>
+	    <center>Frames not supported by your browser!<br></center>
+	  </noframes>
+	</frameset>
+
+	</html>
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# sub write_overview_line(filehandle, basename, line, link)
+#
+#
+
+sub write_overview_line(*$$$)
+{
+	my $y1 = $_[2] - 1;
+	my $y2 = $y1 + $nav_resolution - 1;
+	my $x2 = $overview_width - 1;
+
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	    <area shape="rect" coords="0,$y1,$x2,$y2" href="$_[1].gcov.$html_ext#$_[3]" target="source" alt="overview">
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+#
+# write_overview(filehandle, basedir, basename, pagetitle, lines)
+#
+#
+
+sub write_overview(*$$$$)
+{
+	my $index;
+	my $max_line = $_[4] - 1;
+	my $offset;
+
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+	<html lang="en">
+
+	<head>
+	  <title>$_[3]</title>
+	  <meta http-equiv="Content-Type" content="text/html; charset=$charset">
+	  <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
+	</head>
+
+	<body>
+	  <map name="overview">
+END_OF_HTML
+	;
+
+	# *************************************************************
+
+	# Make $offset the next higher multiple of $nav_resolution
+	$offset = ($nav_offset + $nav_resolution - 1) / $nav_resolution;
+	$offset = sprintf("%d", $offset ) * $nav_resolution;
+
+	# Create image map for overview image
+	for ($index = 1; $index <= $_[4]; $index += $nav_resolution)
+	{
+		# Enforce nav_offset
+		if ($index < $offset + 1)
+		{
+			write_overview_line($_[0], $_[2], $index, 1);
+		}
+		else
+		{
+			write_overview_line($_[0], $_[2], $index, $index - $offset);
+		}
+	}
+
+	# *************************************************************
+
+	write_html($_[0], <<END_OF_HTML)
+	  </map>
+
+	  <center>
+	  <a href="$_[2].gcov.$html_ext#top" target="source">Top</a><br><br>
+	  <img src="$_[2].gcov.png" width=$overview_width height=$max_line alt="Overview" border=0 usemap="#overview">
+	  </center>
+	</body>
+	</html>
+END_OF_HTML
+	;
+
+	# *************************************************************
+}
+
+
+sub max($$)
+{
+	my ($a, $b) = @_;
+
+	return $a if ($a > $b);
+	return $b;
+}
+
+
+#
+# write_header(filehandle, type, trunc_file_name, rel_file_name, lines_found,
+# lines_hit, funcs_found, funcs_hit, sort_type)
+#
+# Write a complete standard page header. TYPE may be (0, 1, 2, 3, 4)
+# corresponding to (directory view header, file view header, source view
+# header, test case description header, function view header)
+#
+
+sub write_header(*$$$$$$$$$$)
+{
+	local *HTML_HANDLE = $_[0];
+	my $type = $_[1];
+	my $trunc_name = $_[2];
+	my $rel_filename = $_[3];
+	my $lines_found = $_[4];
+	my $lines_hit = $_[5];
+	my $fn_found = $_[6];
+	my $fn_hit = $_[7];
+	my $br_found = $_[8];
+	my $br_hit = $_[9];
+	my $sort_type = $_[10];
+	my $base_dir;
+	my $view;
+	my $test;
+	my $base_name;
+	my $style;
+	my $rate;
+	my @row_left;
+	my @row_right;
+	my $num_rows;
+	my $i;
+	my $esc_trunc_name = escape_html($trunc_name);
+
+	$base_name = basename($rel_filename);
+
+	# Prepare text for "current view" field
+	if ($type == $HDR_DIR)
+	{
+		# Main overview
+		$base_dir = "";
+		$view = $overview_title;
+	}
+	elsif ($type == $HDR_FILE)
+	{
+		# Directory overview
+		$base_dir = get_relative_base_path($rel_filename);
+		$view = "<a href=\"$base_dir"."index.$html_ext\">".
+			"$overview_title</a> - $esc_trunc_name";
+	}
+	elsif ($type == $HDR_SOURCE || $type == $HDR_FUNC)
+	{
+		# File view
+		my $dir_name = dirname($rel_filename);
+		my $esc_base_name = escape_html($base_name);
+		my $esc_dir_name = escape_html($dir_name);
+
+		$base_dir = get_relative_base_path($dir_name);
+		if ($frames)
+		{
+			# Need to break frameset when clicking any of these
+			# links
+			$view = "<a href=\"$base_dir"."index.$html_ext\" ".
+				"target=\"_parent\">$overview_title</a> - ".
+				"<a href=\"index.$html_ext\" target=\"_parent\">".
+				"$esc_dir_name</a> - $esc_base_name";
+		}
+		else
+		{
+			$view = "<a href=\"$base_dir"."index.$html_ext\">".
+				"$overview_title</a> - ".
+				"<a href=\"index.$html_ext\">".
+				"$esc_dir_name</a> - $esc_base_name";
+		}
+
+		# Add function suffix
+		if ($func_coverage) {
+			$view .= "<span style=\"font-size: 80%;\">";
+			if ($type == $HDR_SOURCE) {
+				if ($sort) {
+					$view .= " (source / <a href=\"$base_name.func-sort-c.$html_ext\">functions</a>)";
+				} else {
+					$view .= " (source / <a href=\"$base_name.func.$html_ext\">functions</a>)";
+				}
+			} elsif ($type == $HDR_FUNC) {
+				$view .= " (<a href=\"$base_name.gcov.$html_ext\">source</a> / functions)";
+			}
+			$view .= "</span>";
+		}
+	}
+	elsif ($type == $HDR_TESTDESC)
+	{
+		# Test description header
+		$base_dir = "";
+		$view = "<a href=\"$base_dir"."index.$html_ext\">".
+			"$overview_title</a> - test case descriptions";
+	}
+
+	# Prepare text for "test" field
+	$test = escape_html($test_title);
+
+	# Append link to test description page if available
+	if (%test_description && ($type != $HDR_TESTDESC))
+	{
+		if ($frames && ($type == $HDR_SOURCE || $type == $HDR_FUNC))
+		{
+			# Need to break frameset when clicking this link
+			$test .= " ( <span style=\"font-size:80%;\">".
+				 "<a href=\"$base_dir".
+				 "descriptions.$html_ext\" target=\"_parent\">".
+				 "view descriptions</a></span> )";
+		}
+		else
+		{
+			$test .= " ( <span style=\"font-size:80%;\">".
+				 "<a href=\"$base_dir".
+				 "descriptions.$html_ext\">".
+				 "view descriptions</a></span> )";
+		}
+	}
+
+	# Write header
+	write_header_prolog(*HTML_HANDLE, $base_dir);
+
+	# Left row
+	push(@row_left, [[ "10%", "headerItem", "Current view:" ],
+			 [ "35%", "headerValue", $view ]]);
+	push(@row_left, [[undef, "headerItem", "Test:"],
+			 [undef, "headerValue", $test]]);
+	push(@row_left, [[undef, "headerItem", "Date:"],
+			 [undef, "headerValue", $date]]);
+
+	# Right row
+	if ($legend && ($type == $HDR_SOURCE || $type == $HDR_FUNC)) {
+		my $text = <<END_OF_HTML;
+            Lines:
+            <span class="coverLegendCov">hit</span>
+            <span class="coverLegendNoCov">not hit</span>
+END_OF_HTML
+		if ($br_coverage) {
+			$text .= <<END_OF_HTML;
+            | Branches:
+            <span class="coverLegendCov">+</span> taken
+            <span class="coverLegendNoCov">-</span> not taken
+            <span class="coverLegendNoCov">#</span> not executed
+END_OF_HTML
+		}
+		push(@row_left, [[undef, "headerItem", "Legend:"],
+				 [undef, "headerValueLeg", $text]]);
+	} elsif ($legend && ($type != $HDR_TESTDESC)) {
+		my $text = <<END_OF_HTML;
+	    Rating:
+            <span class="coverLegendCovLo" title="Coverage rates below $med_limit % are classified as low">low: &lt; $med_limit %</span>
+            <span class="coverLegendCovMed" title="Coverage rates between $med_limit % and $hi_limit % are classified as medium">medium: &gt;= $med_limit %</span>
+            <span class="coverLegendCovHi" title="Coverage rates of $hi_limit % and more are classified as high">high: &gt;= $hi_limit %</span>
+END_OF_HTML
+		push(@row_left, [[undef, "headerItem", "Legend:"],
+				 [undef, "headerValueLeg", $text]]);
+	}
+	if ($type == $HDR_TESTDESC) {
+		push(@row_right, [[ "55%" ]]);
+	} else {
+		push(@row_right, [["15%", undef, undef ],
+				  ["10%", "headerCovTableHead", "Hit" ],
+				  ["10%", "headerCovTableHead", "Total" ],
+				  ["15%", "headerCovTableHead", "Coverage"]]);
+	}
+	# Line coverage
+	$style = $rate_name[classify_rate($lines_found, $lines_hit,
+					  $med_limit, $hi_limit)];
+	$rate = rate($lines_hit, $lines_found, " %");
+	push(@row_right, [[undef, "headerItem", "Lines:"],
+			  [undef, "headerCovTableEntry", $lines_hit],
+			  [undef, "headerCovTableEntry", $lines_found],
+			  [undef, "headerCovTableEntry$style", $rate]])
+			if ($type != $HDR_TESTDESC);
+	# Function coverage
+	if ($func_coverage) {
+		$style = $rate_name[classify_rate($fn_found, $fn_hit,
+						  $fn_med_limit, $fn_hi_limit)];
+		$rate = rate($fn_hit, $fn_found, " %");
+		push(@row_right, [[undef, "headerItem", "Functions:"],
+				  [undef, "headerCovTableEntry", $fn_hit],
+				  [undef, "headerCovTableEntry", $fn_found],
+				  [undef, "headerCovTableEntry$style", $rate]])
+			if ($type != $HDR_TESTDESC);
+	}
+	# Branch coverage
+	if ($br_coverage) {
+		$style = $rate_name[classify_rate($br_found, $br_hit,
+						  $br_med_limit, $br_hi_limit)];
+		$rate = rate($br_hit, $br_found, " %");
+		push(@row_right, [[undef, "headerItem", "Branches:"],
+				  [undef, "headerCovTableEntry", $br_hit],
+				  [undef, "headerCovTableEntry", $br_found],
+				  [undef, "headerCovTableEntry$style", $rate]])
+			if ($type != $HDR_TESTDESC);
+	}
+
+	# Print rows
+	$num_rows = max(scalar(@row_left), scalar(@row_right));
+	for ($i = 0; $i < $num_rows; $i++) {
+		my $left = $row_left[$i];
+		my $right = $row_right[$i];
+
+		if (!defined($left)) {
+			$left = [[undef, undef, undef], [undef, undef, undef]];
+		}
+		if (!defined($right)) {
+			$right = [];
+		}
+		write_header_line(*HTML_HANDLE, @{$left},
+				  [ $i == 0 ? "5%" : undef, undef, undef],
+				  @{$right});
+	}
+
+	# Fourth line
+	write_header_epilog(*HTML_HANDLE, $base_dir);
+}
+
+sub get_sorted_by_rate($$)
+{
+	my ($hash, $type) = @_;
+
+	if ($type == $SORT_LINE) {
+		# Sort by line coverage
+		return sort({$hash->{$a}[7] <=> $hash->{$b}[7]} keys(%{$hash}));
+	} elsif ($type == $SORT_FUNC) {
+		# Sort by function coverage;
+		return sort({$hash->{$a}[8] <=> $hash->{$b}[8]}	keys(%{$hash}));
+	} elsif ($type == $SORT_BRANCH) {
+		# Sort by br coverage;
+		return sort({$hash->{$a}[9] <=> $hash->{$b}[9]}	keys(%{$hash}));
+	}
+}
+
+sub get_sorted_by_missed($$)
+{
+	my ($hash, $type) = @_;
+
+	if ($type == $SORT_LINE) {
+		# Sort by number of instrumented lines without coverage
+		return sort(
+			{
+				($hash->{$b}[0] - $hash->{$b}[1]) <=>
+				($hash->{$a}[0] - $hash->{$a}[1])
+			} keys(%{$hash}));
+	} elsif ($type == $SORT_FUNC) {
+		# Sort by number of instrumented functions without coverage
+		return sort(
+			{
+				($hash->{$b}[2] - $hash->{$b}[3]) <=>
+				($hash->{$a}[2] - $hash->{$a}[3])
+			} keys(%{$hash}));
+	} elsif ($type == $SORT_BRANCH) {
+		# Sort by number of instrumented branches without coverage
+		return sort(
+			{
+				($hash->{$b}[4] - $hash->{$b}[5]) <=>
+				($hash->{$a}[4] - $hash->{$a}[5])
+			} keys(%{$hash}));
+	}
+}
+
+#
+# get_sorted_keys(hash_ref, sort_type)
+#
+# hash_ref: filename -> stats
+# stats: [ lines_found, lines_hit, fn_found, fn_hit, br_found, br_hit,
+#          link_name, line_rate, fn_rate, br_rate ]
+#
+
+sub get_sorted_keys($$)
+{
+	my ($hash, $type) = @_;
+
+	if ($type == $SORT_FILE) {
+		# Sort by name
+		return sort(keys(%{$hash}));
+	} elsif ($opt_missed) {
+		return get_sorted_by_missed($hash, $type);
+	} else {
+		return get_sorted_by_rate($hash, $type);
+	}
+}
+
+sub get_sort_code($$$)
+{
+	my ($link, $alt, $base) = @_;
+	my $png;
+	my $link_start;
+	my $link_end;
+
+	if (!defined($link)) {
+		$png = "glass.png";
+		$link_start = "";
+		$link_end = "";
+	} else {
+		$png = "updown.png";
+		$link_start = '<a href="'.$link.'">';
+		$link_end = "</a>";
+	}
+
+	return ' <span class="tableHeadSort">'.$link_start.
+	       '<img src="'.$base.$png.'" width=10 height=14 '.
+	       'alt="'.$alt.'" title="'.$alt.'" border=0>'.$link_end.'</span>';
+}
+
+sub get_file_code($$$$)
+{
+	my ($type, $text, $sort_button, $base) = @_;
+	my $result = $text;
+	my $link;
+
+	if ($sort_button) {
+		if ($type == $HEAD_NO_DETAIL) {
+			$link = "index.$html_ext";
+		} else {
+			$link = "index-detail.$html_ext";
+		}
+	}
+	$result .= get_sort_code($link, "Sort by name", $base);
+
+	return $result;
+}
+
+sub get_line_code($$$$$)
+{
+	my ($type, $sort_type, $text, $sort_button, $base) = @_;
+	my $result = $text;
+	my $sort_link;
+
+	if ($type == $HEAD_NO_DETAIL) {
+		# Just text
+		if ($sort_button) {
+			$sort_link = "index-sort-l.$html_ext";
+		}
+	} elsif ($type == $HEAD_DETAIL_HIDDEN) {
+		# Text + link to detail view
+		$result .= ' ( <a class="detail" href="index-detail'.
+			   $fileview_sortname[$sort_type].'.'.$html_ext.
+			   '">show details</a> )';
+		if ($sort_button) {
+			$sort_link = "index-sort-l.$html_ext";
+		}
+	} else {
+		# Text + link to standard view
+		$result .= ' ( <a class="detail" href="index'.
+			   $fileview_sortname[$sort_type].'.'.$html_ext.
+			   '">hide details</a> )';
+		if ($sort_button) {
+			$sort_link = "index-detail-sort-l.$html_ext";
+		}
+	}
+	# Add sort button
+	$result .= get_sort_code($sort_link, "Sort by line coverage", $base);
+
+	return $result;
+}
+
+sub get_func_code($$$$)
+{
+	my ($type, $text, $sort_button, $base) = @_;
+	my $result = $text;
+	my $link;
+
+	if ($sort_button) {
+		if ($type == $HEAD_NO_DETAIL) {
+			$link = "index-sort-f.$html_ext";
+		} else {
+			$link = "index-detail-sort-f.$html_ext";
+		}
+	}
+	$result .= get_sort_code($link, "Sort by function coverage", $base);
+	return $result;
+}
+
+sub get_br_code($$$$)
+{
+	my ($type, $text, $sort_button, $base) = @_;
+	my $result = $text;
+	my $link;
+
+	if ($sort_button) {
+		if ($type == $HEAD_NO_DETAIL) {
+			$link = "index-sort-b.$html_ext";
+		} else {
+			$link = "index-detail-sort-b.$html_ext";
+		}
+	}
+	$result .= get_sort_code($link, "Sort by branch coverage", $base);
+	return $result;
+}
+
+#
+# write_file_table(filehandle, base_dir, overview, testhash, testfnchash,
+#                  testbrhash, fileview, sort_type)
+#
+# Write a complete file table. OVERVIEW is a reference to a hash containing
+# the following mapping:
+#
+#   filename -> "lines_found,lines_hit,funcs_found,funcs_hit,page_link,
+#		 func_link"
+#
+# TESTHASH is a reference to the following hash:
+#
+#   filename -> \%testdata
+#   %testdata: name of test affecting this file -> \%testcount
+#   %testcount: line number -> execution count for a single test
+#
+# Heading of first column is "Filename" if FILEVIEW is true, "Directory name"
+# otherwise.
+#
+
+sub write_file_table(*$$$$$$$)
+{
+	local *HTML_HANDLE = $_[0];
+	my $base_dir = $_[1];
+	my $overview = $_[2];
+	my $testhash = $_[3];
+	my $testfnchash = $_[4];
+	my $testbrhash = $_[5];
+	my $fileview = $_[6];
+	my $sort_type = $_[7];
+	my $filename;
+	my $bar_graph;
+	my $hit;
+	my $found;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+	my $page_link;
+	my $testname;
+	my $testdata;
+	my $testfncdata;
+	my $testbrdata;
+	my %affecting_tests;
+	my $line_code = "";
+	my $func_code;
+	my $br_code;
+	my $file_code;
+	my @head_columns;
+
+	# Determine HTML code for column headings
+	if (($base_dir ne "") && $show_details)
+	{
+		my $detailed = keys(%{$testhash});
+
+		$file_code = get_file_code($detailed ? $HEAD_DETAIL_HIDDEN :
+					$HEAD_NO_DETAIL,
+					$fileview ? "Filename" : "Directory",
+					$sort && $sort_type != $SORT_FILE,
+					$base_dir);
+		$line_code = get_line_code($detailed ? $HEAD_DETAIL_SHOWN :
+					$HEAD_DETAIL_HIDDEN,
+					$sort_type,
+					"Line Coverage",
+					$sort && $sort_type != $SORT_LINE,
+					$base_dir);
+		$func_code = get_func_code($detailed ? $HEAD_DETAIL_HIDDEN :
+					$HEAD_NO_DETAIL,
+					"Functions",
+					$sort && $sort_type != $SORT_FUNC,
+					$base_dir);
+		$br_code = get_br_code($detailed ? $HEAD_DETAIL_HIDDEN :
+					$HEAD_NO_DETAIL,
+					"Branches",
+					$sort && $sort_type != $SORT_BRANCH,
+					$base_dir);
+	} else {
+		$file_code = get_file_code($HEAD_NO_DETAIL,
+					$fileview ? "Filename" : "Directory",
+					$sort && $sort_type != $SORT_FILE,
+					$base_dir);
+		$line_code = get_line_code($HEAD_NO_DETAIL, $sort_type, "Line Coverage",
+					$sort && $sort_type != $SORT_LINE,
+					$base_dir);
+		$func_code = get_func_code($HEAD_NO_DETAIL, "Functions",
+					$sort && $sort_type != $SORT_FUNC,
+					$base_dir);
+		$br_code = get_br_code($HEAD_NO_DETAIL, "Branches",
+					$sort && $sort_type != $SORT_BRANCH,
+					$base_dir);
+	}
+	push(@head_columns, [ $line_code, 3 ]);
+	push(@head_columns, [ $func_code, 2]) if ($func_coverage);
+	push(@head_columns, [ $br_code, 2]) if ($br_coverage);
+
+	write_file_table_prolog(*HTML_HANDLE, $file_code, @head_columns);
+
+	foreach $filename (get_sorted_keys($overview, $sort_type))
+	{
+		my @columns;
+		($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit,
+		 $page_link) = @{$overview->{$filename}};
+
+		# Line coverage
+		push(@columns, [$found, $hit, $med_limit, $hi_limit, 1]);
+		# Function coverage
+		if ($func_coverage) {
+			push(@columns, [$fn_found, $fn_hit, $fn_med_limit,
+					$fn_hi_limit, 0]);
+		}
+		# Branch coverage
+		if ($br_coverage) {
+			push(@columns, [$br_found, $br_hit, $br_med_limit,
+					$br_hi_limit, 0]);
+		}
+		write_file_table_entry(*HTML_HANDLE, $base_dir, $filename,
+				       $page_link, @columns);
+
+		$testdata = $testhash->{$filename};
+		$testfncdata = $testfnchash->{$filename};
+		$testbrdata = $testbrhash->{$filename};
+
+		# Check whether we should write test specific coverage
+		# as well
+		if (!($show_details && $testdata)) { next; }
+
+		# Filter out those tests that actually affect this file
+		%affecting_tests = %{ get_affecting_tests($testdata,
+					$testfncdata, $testbrdata) };
+
+		# Does any of the tests affect this file at all?
+		if (!%affecting_tests) { next; }
+
+		foreach $testname (keys(%affecting_tests))
+		{
+			my @results;
+			($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
+				split(",", $affecting_tests{$testname});
+
+			# Insert link to description of available
+			if ($test_description{$testname})
+			{
+				$testname = "<a href=\"$base_dir".
+					    "descriptions.$html_ext#$testname\">".
+					    "$testname</a>";
+			}
+
+			push(@results, [$found, $hit]);
+			push(@results, [$fn_found, $fn_hit]) if ($func_coverage);
+			push(@results, [$br_found, $br_hit]) if ($br_coverage);
+			write_file_table_detail_entry(*HTML_HANDLE, $testname,
+				@results);
+		}
+	}
+
+	write_file_table_epilog(*HTML_HANDLE);
+}
+
+
+#
+# get_found_and_hit(hash)
+#
+# Return the count for entries (found) and entries with an execution count
+# greater than zero (hit) in a hash (linenumber -> execution count) as
+# a list (found, hit)
+#
+
+sub get_found_and_hit($)
+{
+	my %hash = %{$_[0]};
+	my $found = 0;
+	my $hit = 0;
+
+	# Calculate sum
+	$found = 0;
+	$hit = 0;
+			
+	foreach (keys(%hash))
+	{
+		$found++;
+		if ($hash{$_}>0) { $hit++; }
+	}
+
+	return ($found, $hit);
+}
+
+
+#
+# get_func_found_and_hit(sumfnccount)
+#
+# Return (f_found, f_hit) for sumfnccount
+#
+
+sub get_func_found_and_hit($)
+{
+	my ($sumfnccount) = @_;
+	my $function;
+	my $fn_found;
+	my $fn_hit;
+
+	$fn_found = scalar(keys(%{$sumfnccount}));
+	$fn_hit = 0;
+	foreach $function (keys(%{$sumfnccount})) {
+		if ($sumfnccount->{$function} > 0) {
+			$fn_hit++;
+		}
+	}
+	return ($fn_found, $fn_hit);
+}
+
+
+sub get_br_found_and_hit($)
+{
+	my ($brcount) = @_;
+	my $db;
+
+	$db = brcount_to_db($brcount);
+
+	return brcount_db_get_found_and_hit($db);
+}
+
+
+#
+# get_affecting_tests(testdata, testfncdata, testbrdata)
+#
+# HASHREF contains a mapping filename -> (linenumber -> exec count). Return
+# a hash containing mapping filename -> "lines found, lines hit" for each
+# filename which has a nonzero hit count.
+#
+
+sub get_affecting_tests($$$)
+{
+	my ($testdata, $testfncdata, $testbrdata) = @_;
+	my $testname;
+	my $testcount;
+	my $testfnccount;
+	my $testbrcount;
+	my %result;
+	my $found;
+	my $hit;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+
+	foreach $testname (keys(%{$testdata}))
+	{
+		# Get (line number -> count) hash for this test case
+		$testcount = $testdata->{$testname};
+		$testfnccount = $testfncdata->{$testname};
+		$testbrcount = $testbrdata->{$testname};
+
+		# Calculate sum
+		($found, $hit) = get_found_and_hit($testcount);
+		($fn_found, $fn_hit) = get_func_found_and_hit($testfnccount);
+		($br_found, $br_hit) = get_br_found_and_hit($testbrcount);
+
+		if ($hit>0)
+		{
+			$result{$testname} = "$found,$hit,$fn_found,$fn_hit,".
+					     "$br_found,$br_hit";
+		}
+	}
+
+	return(\%result);
+}
+
+
+sub get_hash_reverse($)
+{
+	my ($hash) = @_;
+	my %result;
+
+	foreach (keys(%{$hash})) {
+		$result{$hash->{$_}} = $_;
+	}
+
+	return \%result;
+}
+
+#
+# write_source(filehandle, source_filename, count_data, checksum_data,
+#              converted_data, func_data, sumbrcount)
+#
+# Write an HTML view of a source code file. Returns a list containing
+# data as needed by gen_png().
+#
+# Die on error.
+#
+
+sub write_source($$$$$$$)
+{
+	local *HTML_HANDLE = $_[0];
+	local *SOURCE_HANDLE;
+	my $source_filename = $_[1];
+	my %count_data;
+	my $line_number;
+	my @result;
+	my $checkdata = $_[3];
+	my $converted = $_[4];
+	my $funcdata  = $_[5];
+	my $sumbrcount = $_[6];
+	my $datafunc = get_hash_reverse($funcdata);
+	my @file;
+
+	if ($_[2])
+	{
+		%count_data = %{$_[2]};
+	}
+
+	if (!open(SOURCE_HANDLE, "<", $source_filename)) {
+		my @lines;
+		my $last_line = 0;
+
+		if (!$ignore[$ERROR_SOURCE]) {
+			die("ERROR: cannot read $source_filename\n");
+		}
+
+		# Continue without source file
+		warn("WARNING: cannot read $source_filename!\n");
+
+		@lines = sort( { $a <=> $b }  keys(%count_data));
+		if (@lines) {
+			$last_line = $lines[scalar(@lines) - 1];
+		}
+		return ( ":" ) if ($last_line < 1);
+
+		# Simulate gcov behavior
+		for ($line_number = 1; $line_number <= $last_line;
+		     $line_number++) {
+			push(@file, "/* EOF */");
+		}
+	} else {
+		@file = <SOURCE_HANDLE>;
+	}
+	
+	write_source_prolog(*HTML_HANDLE);
+	$line_number = 0;
+	foreach (@file) {
+		$line_number++;
+		chomp($_);
+
+		# Also remove CR from line-end
+		s/\015$//;
+
+		# Source code matches coverage data?
+		if (defined($checkdata->{$line_number}) &&
+		    ($checkdata->{$line_number} ne md5_base64($_)))
+		{
+			die("ERROR: checksum mismatch  at $source_filename:".
+			    "$line_number\n");
+		}
+
+		push (@result,
+		      write_source_line(HTML_HANDLE, $line_number,
+					$_, $count_data{$line_number},
+					$converted->{$line_number},
+					$sumbrcount->{$line_number}));
+	}
+
+	close(SOURCE_HANDLE);
+	write_source_epilog(*HTML_HANDLE);
+	return(@result);
+}
+
+
+sub funcview_get_func_code($$$)
+{
+	my ($name, $base, $type) = @_;
+	my $result;
+	my $link;
+
+	if ($sort && $type == 1) {
+		$link = "$name.func.$html_ext";
+	}
+	$result = "Function Name";
+	$result .= get_sort_code($link, "Sort by function name", $base);
+
+	return $result;
+}
+
+sub funcview_get_count_code($$$)
+{
+	my ($name, $base, $type) = @_;
+	my $result;
+	my $link;
+
+	if ($sort && $type == 0) {
+		$link = "$name.func-sort-c.$html_ext";
+	}
+	$result = "Hit count";
+	$result .= get_sort_code($link, "Sort by hit count", $base);
+
+	return $result;
+}
+
+#
+# funcview_get_sorted(funcdata, sumfncdata, sort_type)
+#
+# Depending on the value of sort_type, return a list of functions sorted
+# by name (type 0) or by the associated call count (type 1).
+#
+
+sub funcview_get_sorted($$$)
+{
+	my ($funcdata, $sumfncdata, $type) = @_;
+
+	if ($type == 0) {
+		return sort(keys(%{$funcdata}));
+	}
+	return sort({
+		$sumfncdata->{$b} == $sumfncdata->{$a} ?
+			$a cmp $b : $sumfncdata->{$a} <=> $sumfncdata->{$b}
+		} keys(%{$sumfncdata}));
+}
+
+sub demangle_list($)
+{
+	my ($list) = @_;
+	my $tmpfile;
+	my $handle;
+	my %demangle;
+	my $demangle_arg = "";
+	my %versions;
+
+	# Write function names to file
+	($handle, $tmpfile) = tempfile();
+	die("ERROR: could not create temporary file") if (!defined($tmpfile));
+	print($handle join("\n", @$list));
+	close($handle);
+
+	# Extra flag necessary on OS X so that symbols listed by gcov get demangled
+	# properly.
+	if ($^O eq "darwin") {
+		$demangle_arg = "--no-strip-underscores";
+	}
+
+	# Build translation hash from c++filt output
+	open($handle, "-|", "c++filt $demangle_arg < $tmpfile") or
+		die("ERROR: could not run c++filt: $!\n");
+	foreach my $func (@$list) {
+		my $translated = <$handle>;
+		my $version;
+
+		last if (!defined($translated));
+		chomp($translated);
+
+		$version = ++$versions{$translated};
+		$translated .= ".$version" if ($version > 1);
+		$demangle{$func} = $translated;
+	}
+	close($handle);
+
+	if (scalar(keys(%demangle)) != scalar(@$list)) {
+		die("ERROR: c++filt output not as expected (".
+		    scalar(keys(%demangle))." vs ".scalar(@$list).") lines\n");
+	}
+
+	unlink($tmpfile) or
+		warn("WARNING: could not remove temporary file $tmpfile: $!\n");
+
+	return \%demangle;
+}
+
+#
+# write_function_table(filehandle, source_file, sumcount, funcdata,
+#		       sumfnccount, testfncdata, sumbrcount, testbrdata,
+#		       base_name, base_dir, sort_type)
+#
+# Write an HTML table listing all functions in a source file, including
+# also function call counts and line coverages inside of each function.
+#
+# Die on error.
+#
+
+sub write_function_table(*$$$$$$$$$$)
+{
+	local *HTML_HANDLE = $_[0];
+	my $source = $_[1];
+	my $sumcount = $_[2];
+	my $funcdata = $_[3];
+	my $sumfncdata = $_[4];
+	my $testfncdata = $_[5];
+	my $sumbrcount = $_[6];
+	my $testbrdata = $_[7];
+	my $name = $_[8];
+	my $base = $_[9];
+	my $type = $_[10];
+	my $func;
+	my $func_code;
+	my $count_code;
+	my $demangle;
+
+	# Get HTML code for headings
+	$func_code = funcview_get_func_code($name, $base, $type);
+	$count_code = funcview_get_count_code($name, $base, $type);
+	write_html(*HTML_HANDLE, <<END_OF_HTML)
+	  <center>
+	  <table width="60%" cellpadding=1 cellspacing=1 border=0>
+	    <tr><td><br></td></tr>
+	    <tr>
+	      <td width="80%" class="tableHead">$func_code</td>
+	      <td width="20%" class="tableHead">$count_code</td>
+	    </tr>
+END_OF_HTML
+	;
+
+	# Get demangle translation hash
+	if ($demangle_cpp) {
+		$demangle = demangle_list([ sort(keys(%{$funcdata})) ]);
+	}
+
+	# Get a sorted table
+	foreach $func (funcview_get_sorted($funcdata, $sumfncdata, $type)) {
+		if (!defined($funcdata->{$func}))
+		{
+			next;
+		}
+
+		my $startline = $funcdata->{$func} - $func_offset;
+		my $name = $func;
+		my $count = $sumfncdata->{$name};
+		my $countstyle;
+
+		# Replace function name with demangled version if available
+		$name = $demangle->{$name} if (exists($demangle->{$name}));
+
+		# Escape special characters
+		$name = escape_html($name);
+		if ($startline < 1) {
+			$startline = 1;
+		}
+		if ($count == 0) {
+			$countstyle = "coverFnLo";
+		} else {
+			$countstyle = "coverFnHi";
+		}
+
+		write_html(*HTML_HANDLE, <<END_OF_HTML)
+	    <tr>
+              <td class="coverFn"><a href="$source#$startline">$name</a></td>
+              <td class="$countstyle">$count</td>
+            </tr>
+END_OF_HTML
+                ;
+	}
+	write_html(*HTML_HANDLE, <<END_OF_HTML)
+	  </table>
+	  <br>
+	  </center>
+END_OF_HTML
+	;
+}
+
+
+#
+# info(printf_parameter)
+#
+# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
+# is not set.
+#
+
+sub info(@)
+{
+	if (!$quiet)
+	{
+		# Print info string
+		printf(@_);
+	}
+}
+
+
+#
+# subtract_counts(data_ref, base_ref)
+#
+
+sub subtract_counts($$)
+{
+	my %data = %{$_[0]};
+	my %base = %{$_[1]};
+	my $line;
+	my $data_count;
+	my $base_count;
+	my $hit = 0;
+	my $found = 0;
+
+	foreach $line (keys(%data))
+	{
+		$found++;
+		$data_count = $data{$line};
+		$base_count = $base{$line};
+
+		if (defined($base_count))
+		{
+			$data_count -= $base_count;
+
+			# Make sure we don't get negative numbers
+			if ($data_count<0) { $data_count = 0; }
+		}
+
+		$data{$line} = $data_count;
+		if ($data_count > 0) { $hit++; }
+	}
+
+	return (\%data, $found, $hit);
+}
+
+
+#
+# subtract_fnccounts(data, base)
+#
+# Subtract function call counts found in base from those in data.
+# Return (data, f_found, f_hit).
+#
+
+sub subtract_fnccounts($$)
+{
+	my %data;
+	my %base;
+	my $func;
+	my $data_count;
+	my $base_count;
+	my $fn_hit = 0;
+	my $fn_found = 0;
+
+	%data = %{$_[0]} if (defined($_[0]));
+	%base = %{$_[1]} if (defined($_[1]));
+	foreach $func (keys(%data)) {
+		$fn_found++;
+		$data_count = $data{$func};
+		$base_count = $base{$func};
+
+		if (defined($base_count)) {
+			$data_count -= $base_count;
+
+			# Make sure we don't get negative numbers
+			if ($data_count < 0) {
+				$data_count = 0;
+			}
+		}
+
+		$data{$func} = $data_count;
+		if ($data_count > 0) {
+			$fn_hit++;
+		}
+	}
+
+	return (\%data, $fn_found, $fn_hit);
+}
+
+
+#
+# apply_baseline(data_ref, baseline_ref)
+#
+# Subtract the execution counts found in the baseline hash referenced by
+# BASELINE_REF from actual data in DATA_REF.
+#
+
+sub apply_baseline($$)
+{
+	my %data_hash = %{$_[0]};
+	my %base_hash = %{$_[1]};
+	my $filename;
+	my $testname;
+	my $data;
+	my $data_testdata;
+	my $data_funcdata;
+	my $data_checkdata;
+	my $data_testfncdata;
+	my $data_testbrdata;
+	my $data_count;
+	my $data_testfnccount;
+	my $data_testbrcount;
+	my $base;
+	my $base_checkdata;
+	my $base_sumfnccount;
+	my $base_sumbrcount;
+	my $base_count;
+	my $sumcount;
+	my $sumfnccount;
+	my $sumbrcount;
+	my $found;
+	my $hit;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+
+	foreach $filename (keys(%data_hash))
+	{
+		# Get data set for data and baseline
+		$data = $data_hash{$filename};
+		$base = $base_hash{$filename};
+
+		# Skip data entries for which no base entry exists
+		if (!defined($base))
+		{
+			next;
+		}
+
+		# Get set entries for data and baseline
+		($data_testdata, undef, $data_funcdata, $data_checkdata,
+		 $data_testfncdata, undef, $data_testbrdata) =
+			get_info_entry($data);
+		(undef, $base_count, undef, $base_checkdata, undef,
+		 $base_sumfnccount, undef, $base_sumbrcount) =
+			get_info_entry($base);
+
+		# Check for compatible checksums
+		merge_checksums($data_checkdata, $base_checkdata, $filename);
+
+		# sumcount has to be calculated anew
+		$sumcount = {};
+		$sumfnccount = {};
+		$sumbrcount = {};
+
+		# For each test case, subtract test specific counts
+		foreach $testname (keys(%{$data_testdata}))
+		{
+			# Get counts of both data and baseline
+			$data_count = $data_testdata->{$testname};
+			$data_testfnccount = $data_testfncdata->{$testname};
+			$data_testbrcount = $data_testbrdata->{$testname};
+
+			($data_count, undef, $hit) =
+				subtract_counts($data_count, $base_count);
+			($data_testfnccount) =
+				subtract_fnccounts($data_testfnccount,
+						   $base_sumfnccount);
+			($data_testbrcount) =
+				combine_brcount($data_testbrcount,
+						 $base_sumbrcount, $BR_SUB);
+
+
+			# Check whether this test case did hit any line at all
+			if ($hit > 0)
+			{
+				# Write back resulting hash
+				$data_testdata->{$testname} = $data_count;
+				$data_testfncdata->{$testname} =
+					$data_testfnccount;
+				$data_testbrdata->{$testname} =
+					$data_testbrcount;
+			}
+			else
+			{
+				# Delete test case which did not impact this
+				# file
+				delete($data_testdata->{$testname});
+				delete($data_testfncdata->{$testname});
+				delete($data_testbrdata->{$testname});
+			}
+
+			# Add counts to sum of counts
+			($sumcount, $found, $hit) =
+				add_counts($sumcount, $data_count);
+			($sumfnccount, $fn_found, $fn_hit) =
+				add_fnccount($sumfnccount, $data_testfnccount);
+			($sumbrcount, $br_found, $br_hit) =
+				combine_brcount($sumbrcount, $data_testbrcount,
+						$BR_ADD);
+		}
+
+		# Write back resulting entry
+		set_info_entry($data, $data_testdata, $sumcount, $data_funcdata,
+			       $data_checkdata, $data_testfncdata, $sumfnccount,
+			       $data_testbrdata, $sumbrcount, $found, $hit,
+			       $fn_found, $fn_hit, $br_found, $br_hit);
+
+		$data_hash{$filename} = $data;
+	}
+
+	return (\%data_hash);
+}
+
+
+#
+# remove_unused_descriptions()
+#
+# Removes all test descriptions from the global hash %test_description which
+# are not present in %info_data.
+#
+
+sub remove_unused_descriptions()
+{
+	my $filename;		# The current filename
+	my %test_list;		# Hash containing found test names
+	my $test_data;		# Reference to hash test_name -> count_data
+	my $before;		# Initial number of descriptions
+	my $after;		# Remaining number of descriptions
+	
+	$before = scalar(keys(%test_description));
+
+	foreach $filename (keys(%info_data))
+	{
+		($test_data) = get_info_entry($info_data{$filename});
+		foreach (keys(%{$test_data}))
+		{
+			$test_list{$_} = "";
+		}
+	}
+
+	# Remove descriptions for tests which are not in our list
+	foreach (keys(%test_description))
+	{
+		if (!defined($test_list{$_}))
+		{
+			delete($test_description{$_});
+		}
+	}
+
+	$after = scalar(keys(%test_description));
+	if ($after < $before)
+	{
+		info("Removed ".($before - $after).
+		     " unused descriptions, $after remaining.\n");
+	}
+}
+
+
+#
+# apply_prefix(filename, PREFIXES)
+#
+# If FILENAME begins with PREFIX from PREFIXES, remove PREFIX from FILENAME
+# and return resulting string, otherwise return FILENAME.
+#
+
+sub apply_prefix($@)
+{
+	my $filename = shift;
+	my @dir_prefix = @_;
+
+	if (@dir_prefix)
+	{
+		foreach my $prefix (@dir_prefix)
+		{
+			if ($prefix ne "" && $filename =~ /^\Q$prefix\E\/(.*)$/)
+			{
+				return substr($filename, length($prefix) + 1);
+			}
+		}
+	}
+
+	return $filename;
+}
+
+
+#
+# system_no_output(mode, parameters)
+#
+# Call an external program using PARAMETERS while suppressing depending on
+# the value of MODE:
+#
+#   MODE & 1: suppress STDOUT
+#   MODE & 2: suppress STDERR
+#
+# Return 0 on success, non-zero otherwise.
+#
+
+sub system_no_output($@)
+{
+	my $mode = shift;
+	my $result;
+	local *OLD_STDERR;
+	local *OLD_STDOUT;
+
+	# Save old stdout and stderr handles
+	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
+
+	# Redirect to /dev/null
+	($mode & 1) && open(STDOUT, ">", "/dev/null");
+	($mode & 2) && open(STDERR, ">", "/dev/null");
+
+	system(@_);
+	$result = $?;
+
+	# Close redirected handles
+	($mode & 1) && close(STDOUT);
+	($mode & 2) && close(STDERR);
+
+	# Restore old handles
+	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
+
+	return $result;
+}
+
+
+#
+# read_config(filename)
+#
+# Read configuration file FILENAME and return a reference to a hash containing
+# all valid key=value pairs found.
+#
+
+sub read_config($)
+{
+	my $filename = $_[0];
+	my %result;
+	my $key;
+	my $value;
+	local *HANDLE;
+
+	if (!open(HANDLE, "<", $filename))
+	{
+		warn("WARNING: cannot read configuration file $filename\n");
+		return undef;
+	}
+	while (<HANDLE>)
+	{
+		chomp;
+		# Skip comments
+		s/#.*//;
+		# Remove leading blanks
+		s/^\s+//;
+		# Remove trailing blanks
+		s/\s+$//;
+		next unless length;
+		($key, $value) = split(/\s*=\s*/, $_, 2);
+		if (defined($key) && defined($value))
+		{
+			$result{$key} = $value;
+		}
+		else
+		{
+			warn("WARNING: malformed statement in line $. ".
+			     "of configuration file $filename\n");
+		}
+	}
+	close(HANDLE);
+	return \%result;
+}
+
+
+#
+# apply_config(REF)
+#
+# REF is a reference to a hash containing the following mapping:
+#
+#   key_string => var_ref
+#
+# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
+#
+
+sub apply_config($)
+{
+	my $ref = $_[0];
+
+	foreach (keys(%{$ref}))
+	{
+		if (defined($opt_rc{$_})) {
+			${$ref->{$_}} = $opt_rc{$_};
+		} elsif (defined($config->{$_})) {
+			${$ref->{$_}} = $config->{$_};
+		}
+	}
+}
+
+
+#
+# get_html_prolog(FILENAME)
+#
+# If FILENAME is defined, return contents of file. Otherwise return default
+# HTML prolog. Die on error.
+#
+
+sub get_html_prolog($)
+{
+	my $filename = $_[0];
+	my $result = "";
+
+	if (defined($filename))
+	{
+		local *HANDLE;
+
+		open(HANDLE, "<", $filename)
+			or die("ERROR: cannot open html prolog $filename!\n");
+		while (<HANDLE>)
+		{
+			$result .= $_;
+		}
+		close(HANDLE);
+	}
+	else
+	{
+		$result = <<END_OF_HTML
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html lang="en">
+
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=$charset">
+  <title>\@pagetitle\@</title>
+  <link rel="stylesheet" type="text/css" href="\@basedir\@gcov.css">
+</head>
+
+<body>
+
+END_OF_HTML
+		;
+	}
+
+	return $result;
+}
+
+
+#
+# get_html_epilog(FILENAME)
+#
+# If FILENAME is defined, return contents of file. Otherwise return default
+# HTML epilog. Die on error.
+#
+sub get_html_epilog($)
+{
+	my $filename = $_[0];
+	my $result = "";
+
+	if (defined($filename))
+	{
+		local *HANDLE;
+
+		open(HANDLE, "<", $filename)
+			or die("ERROR: cannot open html epilog $filename!\n");
+		while (<HANDLE>)
+		{
+			$result .= $_;
+		}
+		close(HANDLE);
+	}
+	else
+	{
+		$result = <<END_OF_HTML
+
+</body>
+</html>
+END_OF_HTML
+		;
+	}
+
+	return $result;
+
+}
+
+sub warn_handler($)
+{
+	my ($msg) = @_;
+
+	warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+	my ($msg) = @_;
+
+	die("$tool_name: $msg");
+}
+
+#
+# parse_ignore_errors(@ignore_errors)
+#
+# Parse user input about which errors to ignore.
+#
+
+sub parse_ignore_errors(@)
+{
+	my (@ignore_errors) = @_;
+	my @items;
+	my $item;
+
+	return if (!@ignore_errors);
+
+	foreach $item (@ignore_errors) {
+		$item =~ s/\s//g;
+		if ($item =~ /,/) {
+			# Split and add comma-separated parameters
+			push(@items, split(/,/, $item));
+		} else {
+			# Add single parameter
+			push(@items, $item);
+		}
+	}
+	foreach $item (@items) {
+		my $item_id = $ERROR_ID{lc($item)};
+
+		if (!defined($item_id)) {
+			die("ERROR: unknown argument for --ignore-errors: ".
+			    "$item\n");
+		}
+		$ignore[$item_id] = 1;
+	}
+}
+
+#
+# parse_dir_prefix(@dir_prefix)
+#
+# Parse user input about the prefix list
+#
+
+sub parse_dir_prefix(@)
+{
+	my (@opt_dir_prefix) = @_;
+	my $item;
+
+	return if (!@opt_dir_prefix);
+
+	foreach $item (@opt_dir_prefix) {
+		if ($item =~ /,/) {
+			# Split and add comma-separated parameters
+			push(@dir_prefix, split(/,/, $item));
+		} else {
+			# Add single parameter
+			push(@dir_prefix, $item);
+		}
+	}
+}
+
+#
+# rate(hit, found[, suffix, precision, width])
+#
+# Return the coverage rate [0..100] for HIT and FOUND values. 0 is only
+# returned when HIT is 0. 100 is only returned when HIT equals FOUND.
+# PRECISION specifies the precision of the result. SUFFIX defines a
+# string that is appended to the result if FOUND is non-zero. Spaces
+# are added to the start of the resulting string until it is at least WIDTH
+# characters wide.
+#
+
+sub rate($$;$$$)
+{
+        my ($hit, $found, $suffix, $precision, $width) = @_;
+        my $rate; 
+
+	# Assign defaults if necessary
+	$precision	= $default_precision if (!defined($precision));
+	$suffix		= ""	if (!defined($suffix));
+	$width		= 0	if (!defined($width));
+        
+        return sprintf("%*s", $width, "-") if (!defined($found) || $found == 0);
+        $rate = sprintf("%.*f", $precision, $hit * 100 / $found);
+
+	# Adjust rates if necessary
+        if ($rate == 0 && $hit > 0) {
+		$rate = sprintf("%.*f", $precision, 1 / 10 ** $precision);
+        } elsif ($rate == 100 && $hit != $found) {
+		$rate = sprintf("%.*f", $precision, 100 - 1 / 10 ** $precision);
+	}
+
+	return sprintf("%*s", $width, $rate.$suffix);
+}
diff --git a/externals/lcov/bin/geninfo b/externals/lcov/bin/geninfo
new file mode 100755
index 0000000000000000000000000000000000000000..f41eaec1cdfaadddecec3184eaeb4f7ff93c9890
--- /dev/null
+++ b/externals/lcov/bin/geninfo
@@ -0,0 +1,4014 @@
+#!/usr/bin/env perl
+#
+#   Copyright (c) International Business Machines  Corp., 2002,2012
+#
+#   This program is free software;  you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY;  without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.                 
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program;  if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# geninfo
+#
+#   This script generates .info files from data files as created by code
+#   instrumented with gcc's built-in profiling mechanism. Call it with
+#   --help and refer to the geninfo man page to get information on usage
+#   and available options.
+#
+#
+# Authors:
+#   2002-08-23 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+#                         IBM Lab Boeblingen
+#        based on code by Manoj Iyer <manjo@mail.utexas.edu> and
+#                         Megan Bock <mbock@us.ibm.com>
+#                         IBM Austin
+#   2002-09-05 / Peter Oberparleiter: implemented option that allows file list
+#   2003-04-16 / Peter Oberparleiter: modified read_gcov so that it can also
+#                parse the new gcov format which is to be introduced in gcc 3.3
+#   2003-04-30 / Peter Oberparleiter: made info write to STDERR, not STDOUT
+#   2003-07-03 / Peter Oberparleiter: added line checksum support, added
+#                --no-checksum
+#   2003-09-18 / Nigel Hinds: capture branch coverage data from GCOV
+#   2003-12-11 / Laurent Deniel: added --follow option
+#                workaround gcov (<= 3.2.x) bug with empty .da files
+#   2004-01-03 / Laurent Deniel: Ignore empty .bb files
+#   2004-02-16 / Andreas Krebbel: Added support for .gcno/.gcda files and
+#                gcov versioning
+#   2004-08-09 / Peter Oberparleiter: added configuration file support
+#   2008-07-14 / Tom Zoerner: added --function-coverage command line option
+#   2008-08-13 / Peter Oberparleiter: modified function coverage
+#                implementation (now enabled per default)
+#
+
+use strict;
+use warnings;
+use File::Basename; 
+use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir
+			      splitpath catpath/;
+use Getopt::Long;
+use Digest::MD5 qw(md5_base64);
+use Cwd qw/abs_path/;
+if( $^O eq "msys" )
+{
+	require File::Spec::Win32;
+}
+
+# Constants
+our $tool_dir		= abs_path(dirname($0));
+our $lcov_version	= "LCOV version 1.14";
+our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $gcov_tool		= "gcov";
+our $tool_name		= basename($0);
+
+our $GCOV_VERSION_8_0_0	= 0x80000;
+our $GCOV_VERSION_4_7_0	= 0x40700;
+our $GCOV_VERSION_3_4_0	= 0x30400;
+our $GCOV_VERSION_3_3_0	= 0x30300;
+our $GCNO_FUNCTION_TAG	= 0x01000000;
+our $GCNO_LINES_TAG	= 0x01450000;
+our $GCNO_FILE_MAGIC	= 0x67636e6f;
+our $BBG_FILE_MAGIC	= 0x67626267;
+
+# Error classes which users may specify to ignore during processing
+our $ERROR_GCOV		= 0;
+our $ERROR_SOURCE	= 1;
+our $ERROR_GRAPH	= 2;
+our %ERROR_ID = (
+	"gcov" => $ERROR_GCOV,
+	"source" => $ERROR_SOURCE,
+	"graph" => $ERROR_GRAPH,
+);
+
+our $EXCL_START = "LCOV_EXCL_START";
+our $EXCL_STOP = "LCOV_EXCL_STOP";
+
+# Marker to exclude branch coverage but keep function and line coveage
+our $EXCL_BR_START = "LCOV_EXCL_BR_START";
+our $EXCL_BR_STOP = "LCOV_EXCL_BR_STOP";
+
+# Compatibility mode values
+our $COMPAT_VALUE_OFF	= 0;
+our $COMPAT_VALUE_ON	= 1;
+our $COMPAT_VALUE_AUTO	= 2;
+
+# Compatibility mode value names
+our %COMPAT_NAME_TO_VALUE = (
+	"off"	=> $COMPAT_VALUE_OFF,
+	"on"	=> $COMPAT_VALUE_ON,
+	"auto"	=> $COMPAT_VALUE_AUTO,
+);
+
+# Compatiblity modes
+our $COMPAT_MODE_LIBTOOL	= 1 << 0;
+our $COMPAT_MODE_HAMMER		= 1 << 1;
+our $COMPAT_MODE_SPLIT_CRC	= 1 << 2;
+
+# Compatibility mode names
+our %COMPAT_NAME_TO_MODE = (
+	"libtool"	=> $COMPAT_MODE_LIBTOOL,
+	"hammer"	=> $COMPAT_MODE_HAMMER,
+	"split_crc"	=> $COMPAT_MODE_SPLIT_CRC,
+	"android_4_4_0"	=> $COMPAT_MODE_SPLIT_CRC,
+);
+
+# Map modes to names
+our %COMPAT_MODE_TO_NAME = (
+	$COMPAT_MODE_LIBTOOL	=> "libtool",
+	$COMPAT_MODE_HAMMER	=> "hammer",
+	$COMPAT_MODE_SPLIT_CRC	=> "split_crc",
+);
+
+# Compatibility mode default values
+our %COMPAT_MODE_DEFAULTS = (
+	$COMPAT_MODE_LIBTOOL	=> $COMPAT_VALUE_ON,
+	$COMPAT_MODE_HAMMER	=> $COMPAT_VALUE_AUTO,
+	$COMPAT_MODE_SPLIT_CRC	=> $COMPAT_VALUE_AUTO,
+);
+
+# Compatibility mode auto-detection routines
+sub compat_hammer_autodetect();
+our %COMPAT_MODE_AUTO = (
+	$COMPAT_MODE_HAMMER	=> \&compat_hammer_autodetect,
+	$COMPAT_MODE_SPLIT_CRC	=> 1,	# will be done later
+);
+
+our $BR_LINE		= 0;
+our $BR_BLOCK		= 1;
+our $BR_BRANCH		= 2;
+our $BR_TAKEN		= 3;
+our $BR_VEC_ENTRIES	= 4;
+our $BR_VEC_WIDTH	= 32;
+our $BR_VEC_MAX		= vec(pack('b*', 1 x $BR_VEC_WIDTH), 0, $BR_VEC_WIDTH);
+
+our $UNNAMED_BLOCK	= -1;
+
+# Prototypes
+sub print_usage(*);
+sub transform_pattern($);
+sub gen_info($);
+sub process_dafile($$);
+sub match_filename($@);
+sub solve_ambiguous_match($$$);
+sub split_filename($);
+sub solve_relative_path($$);
+sub read_gcov_header($);
+sub read_gcov_file($);
+sub info(@);
+sub map_llvm_version($);
+sub version_to_str($);
+sub get_gcov_version();
+sub system_no_output($@);
+sub read_config($);
+sub apply_config($);
+sub get_exclusion_data($);
+sub apply_exclusion_data($$);
+sub process_graphfile($$);
+sub filter_fn_name($);
+sub warn_handler($);
+sub die_handler($);
+sub graph_error($$);
+sub graph_expect($);
+sub graph_read(*$;$$);
+sub graph_skip(*$;$);
+sub uniq(@);
+sub sort_uniq(@);
+sub sort_uniq_lex(@);
+sub graph_cleanup($);
+sub graph_find_base($);
+sub graph_from_bb($$$$);
+sub graph_add_order($$$);
+sub read_bb_word(*;$);
+sub read_bb_value(*;$);
+sub read_bb_string(*$);
+sub read_bb($);
+sub read_bbg_word(*;$);
+sub read_bbg_value(*;$);
+sub read_bbg_string(*);
+sub read_bbg_lines_record(*$$$$$);
+sub read_bbg($);
+sub read_gcno_word(*;$$);
+sub read_gcno_value(*$;$$);
+sub read_gcno_string(*$);
+sub read_gcno_lines_record(*$$$$$$);
+sub determine_gcno_split_crc($$$$);
+sub read_gcno_function_record(*$$$$$);
+sub read_gcno($);
+sub get_gcov_capabilities();
+sub get_overall_line($$$$);
+sub print_overall_rate($$$$$$$$$);
+sub br_gvec_len($);
+sub br_gvec_get($$);
+sub debug($);
+sub int_handler();
+sub parse_ignore_errors(@);
+sub is_external($);
+sub compat_name($);
+sub parse_compat_modes($);
+sub is_compat($);
+sub is_compat_auto($);
+
+
+# Global variables
+our $gcov_version;
+our $gcov_version_string;
+our $graph_file_extension;
+our $data_file_extension;
+our @data_directory;
+our $test_name = "";
+our $quiet;
+our $help;
+our $output_filename;
+our $base_directory;
+our $version;
+our $follow;
+our $checksum;
+our $no_checksum;
+our $opt_compat_libtool;
+our $opt_no_compat_libtool;
+our $rc_adjust_src_path;# Regexp specifying parts to remove from source path
+our $adjust_src_pattern;
+our $adjust_src_replace;
+our $adjust_testname;
+our $config;		# Configuration file contents
+our @ignore_errors;	# List of errors to ignore (parameter)
+our @ignore;		# List of errors to ignore (array)
+our $initial;
+our @include_patterns; # List of source file patterns to include
+our @exclude_patterns; # List of source file patterns to exclude
+our %excluded_files; # Files excluded due to include/exclude options
+our $no_recursion = 0;
+our $maxdepth;
+our $no_markers = 0;
+our $opt_derive_func_data = 0;
+our $opt_external = 1;
+our $opt_no_external;
+our $debug = 0;
+our $gcov_caps;
+our @gcov_options;
+our @internal_dirs;
+our $opt_config_file;
+our $opt_gcov_all_blocks = 1;
+our $opt_compat;
+our %opt_rc;
+our %compat_value;
+our $gcno_split_crc;
+our $func_coverage = 1;
+our $br_coverage = 0;
+our $rc_auto_base = 1;
+our $excl_line = "LCOV_EXCL_LINE";
+our $excl_br_line = "LCOV_EXCL_BR_LINE";
+
+our $cwd = `pwd`;
+chomp($cwd);
+
+
+#
+# Code entry point
+#
+
+# Register handler routine to be called when interrupted
+$SIG{"INT"} = \&int_handler;
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+
+# Set LC_ALL so that gcov output will be in a unified format
+$ENV{"LC_ALL"} = "C";
+
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+	   "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
+
+{
+	# Remove spaces around rc options
+	my %new_opt_rc;
+
+	while (my ($key, $value) = each(%opt_rc)) {
+		$key =~ s/^\s+|\s+$//g;
+		$value =~ s/^\s+|\s+$//g;
+
+		$new_opt_rc{$key} = $value;
+	}
+	%opt_rc = %new_opt_rc;
+}
+
+# Read configuration file if available
+if (defined($opt_config_file)) {
+	$config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
+{
+	$config = read_config($ENV{"HOME"}."/.lcovrc");
+}
+elsif (-r "/etc/lcovrc")
+{
+	$config = read_config("/etc/lcovrc");
+} elsif (-r "/usr/local/etc/lcovrc")
+{
+	$config = read_config("/usr/local/etc/lcovrc");
+}
+
+if ($config || %opt_rc)
+{
+	# Copy configuration file and --rc values to variables
+	apply_config({
+		"geninfo_gcov_tool"		=> \$gcov_tool,
+		"geninfo_adjust_testname"	=> \$adjust_testname,
+		"geninfo_checksum"		=> \$checksum,
+		"geninfo_no_checksum"		=> \$no_checksum, # deprecated
+		"geninfo_compat_libtool"	=> \$opt_compat_libtool,
+		"geninfo_external"		=> \$opt_external,
+		"geninfo_gcov_all_blocks"	=> \$opt_gcov_all_blocks,
+		"geninfo_compat"		=> \$opt_compat,
+		"geninfo_adjust_src_path"	=> \$rc_adjust_src_path,
+		"geninfo_auto_base"		=> \$rc_auto_base,
+		"lcov_function_coverage"	=> \$func_coverage,
+		"lcov_branch_coverage"		=> \$br_coverage,
+		"lcov_excl_line"		=> \$excl_line,
+		"lcov_excl_br_line"		=> \$excl_br_line,
+	});
+
+	# Merge options
+	if (defined($no_checksum))
+	{
+		$checksum = ($no_checksum ? 0 : 1);
+		$no_checksum = undef;
+	}
+
+	# Check regexp
+	if (defined($rc_adjust_src_path)) {
+		my ($pattern, $replace) = split(/\s*=>\s*/,
+						$rc_adjust_src_path);
+		local $SIG{__DIE__};
+		eval '$adjust_src_pattern = qr>'.$pattern.'>;';
+		if (!defined($adjust_src_pattern)) {
+			my $msg = $@;
+
+			chomp($msg);
+			$msg =~ s/at \(eval.*$//;
+			warn("WARNING: invalid pattern in ".
+			     "geninfo_adjust_src_path: $msg\n");
+		} elsif (!defined($replace)) {
+			# If no replacement is specified, simply remove pattern
+			$adjust_src_replace = "";
+		} else {
+			$adjust_src_replace = $replace;
+		}
+	}
+	for my $regexp (($excl_line, $excl_br_line)) {
+		eval 'qr/'.$regexp.'/';
+		my $error = $@;
+		chomp($error);
+		$error =~ s/at \(eval.*$//;
+		die("ERROR: invalid exclude pattern: $error") if $error;
+	}
+}
+
+# Parse command line options
+if (!GetOptions("test-name|t=s" => \$test_name,
+		"output-filename|o=s" => \$output_filename,
+		"checksum" => \$checksum,
+		"no-checksum" => \$no_checksum,
+		"base-directory|b=s" => \$base_directory,
+		"version|v" =>\$version,
+		"quiet|q" => \$quiet,
+		"help|h|?" => \$help,
+		"follow|f" => \$follow,
+		"compat-libtool" => \$opt_compat_libtool,
+		"no-compat-libtool" => \$opt_no_compat_libtool,
+		"gcov-tool=s" => \$gcov_tool,
+		"ignore-errors=s" => \@ignore_errors,
+		"initial|i" => \$initial,
+		"include=s" => \@include_patterns,
+		"exclude=s" => \@exclude_patterns,
+		"no-recursion" => \$no_recursion,
+		"no-markers" => \$no_markers,
+		"derive-func-data" => \$opt_derive_func_data,
+		"debug" => \$debug,
+		"external|e" => \$opt_external,
+		"no-external" => \$opt_no_external,
+		"compat=s" => \$opt_compat,
+		"config-file=s" => \$opt_config_file,
+		"rc=s%" => \%opt_rc,
+		))
+{
+	print(STDERR "Use $tool_name --help to get usage information\n");
+	exit(1);
+}
+else
+{
+	# Merge options
+	if (defined($no_checksum))
+	{
+		$checksum = ($no_checksum ? 0 : 1);
+		$no_checksum = undef;
+	}
+
+	if (defined($opt_no_compat_libtool))
+	{
+		$opt_compat_libtool = ($opt_no_compat_libtool ? 0 : 1);
+		$opt_no_compat_libtool = undef;
+	}
+
+	if (defined($opt_no_external)) {
+		$opt_external = 0;
+		$opt_no_external = undef;
+	}
+
+	if(@include_patterns) {
+		# Need perlreg expressions instead of shell pattern
+		@include_patterns = map({ transform_pattern($_); } @include_patterns);
+	}
+
+	if(@exclude_patterns) {
+		# Need perlreg expressions instead of shell pattern
+		@exclude_patterns = map({ transform_pattern($_); } @exclude_patterns);
+	}
+}
+
+@data_directory = @ARGV;
+
+debug("$lcov_version\n");
+
+# Check for help option
+if ($help)
+{
+	print_usage(*STDOUT);
+	exit(0);
+}
+
+# Check for version option
+if ($version)
+{
+	print("$tool_name: $lcov_version\n");
+	exit(0);
+}
+
+# Check gcov tool
+if (system_no_output(3, $gcov_tool, "--help") == -1)
+{
+	die("ERROR: need tool $gcov_tool!\n");
+}
+
+($gcov_version, $gcov_version_string) = get_gcov_version();
+
+# Determine gcov options
+$gcov_caps = get_gcov_capabilities();
+push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'} &&
+			      ($br_coverage || $func_coverage));
+push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'} &&
+			      $br_coverage);
+push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'} &&
+			      $opt_gcov_all_blocks && $br_coverage);
+if ($gcov_caps->{'hash-filenames'})
+{
+	push(@gcov_options, "-x");
+} else {
+	push(@gcov_options, "-p") if ($gcov_caps->{'preserve-paths'});
+}
+
+# Determine compatibility modes
+parse_compat_modes($opt_compat);
+
+# Determine which errors the user wants us to ignore
+parse_ignore_errors(@ignore_errors);
+
+# Make sure test names only contain valid characters
+if ($test_name =~ s/\W/_/g)
+{
+	warn("WARNING: invalid characters removed from testname!\n");
+}
+
+# Adjust test name to include uname output if requested
+if ($adjust_testname)
+{
+	$test_name .= "__".`uname -a`;
+	$test_name =~ s/\W/_/g;
+}
+
+# Make sure base_directory contains an absolute path specification
+if ($base_directory)
+{
+	$base_directory = solve_relative_path($cwd, $base_directory);
+}
+
+# Check for follow option
+if ($follow)
+{
+	$follow = "-follow"
+}
+else
+{
+	$follow = "";
+}
+
+# Determine checksum mode
+if (defined($checksum))
+{
+	# Normalize to boolean
+	$checksum = ($checksum ? 1 : 0);
+}
+else
+{
+	# Default is off
+	$checksum = 0;
+}
+
+# Determine max depth for recursion
+if ($no_recursion)
+{
+	$maxdepth = "-maxdepth 1";
+}
+else
+{
+	$maxdepth = "";
+}
+
+# Check for directory name
+if (!@data_directory)
+{
+	die("No directory specified\n".
+	    "Use $tool_name --help to get usage information\n");
+}
+else
+{
+	foreach (@data_directory)
+	{
+		stat($_);
+		if (!-r _)
+		{
+			die("ERROR: cannot read $_!\n");
+		}
+	}
+}
+
+if ($gcov_version < $GCOV_VERSION_3_4_0)
+{
+	if (is_compat($COMPAT_MODE_HAMMER))
+	{
+		$data_file_extension = ".da";
+		$graph_file_extension = ".bbg";
+	}
+	else
+	{
+		$data_file_extension = ".da";
+		$graph_file_extension = ".bb";
+	}
+}
+else
+{
+	$data_file_extension = ".gcda";
+	$graph_file_extension = ".gcno";
+}	
+
+# Check output filename
+if (defined($output_filename) && ($output_filename ne "-"))
+{
+	# Initially create output filename, data is appended
+	# for each data file processed
+	local *DUMMY_HANDLE;
+	open(DUMMY_HANDLE, ">", $output_filename)
+		or die("ERROR: cannot create $output_filename!\n");
+	close(DUMMY_HANDLE);
+
+	# Make $output_filename an absolute path because we're going
+	# to change directories while processing files
+	if (!($output_filename =~ /^\/(.*)$/))
+	{
+		$output_filename = $cwd."/".$output_filename;
+	}
+}
+
+# Build list of directories to identify external files
+foreach my $entry(@data_directory, $base_directory) {
+	next if (!defined($entry));
+	push(@internal_dirs, solve_relative_path($cwd, $entry));
+}
+
+# Do something
+foreach my $entry (@data_directory) {
+	gen_info($entry);
+}
+
+if ($initial && $br_coverage) {
+	warn("Note: --initial does not generate branch coverage ".
+	     "data\n");
+}
+info("Finished .info-file creation\n");
+
+exit(0);
+
+
+
+#
+# print_usage(handle)
+#
+# Print usage information.
+#
+
+sub print_usage(*)
+{
+	local *HANDLE = $_[0];
+
+	print(HANDLE <<END_OF_USAGE);
+Usage: $tool_name [OPTIONS] DIRECTORY
+
+Traverse DIRECTORY and create a .info file for each data file found. Note
+that you may specify more than one directory, all of which are then processed
+sequentially.
+
+  -h, --help                        Print this help, then exit
+  -v, --version                     Print version number, then exit
+  -q, --quiet                       Do not print progress messages
+  -i, --initial                     Capture initial zero coverage data
+  -t, --test-name NAME              Use test case name NAME for resulting data
+  -o, --output-filename OUTFILE     Write data only to OUTFILE
+  -f, --follow                      Follow links when searching .da/.gcda files
+  -b, --base-directory DIR          Use DIR as base directory for relative paths
+      --(no-)checksum               Enable (disable) line checksumming
+      --(no-)compat-libtool         Enable (disable) libtool compatibility mode
+      --gcov-tool TOOL              Specify gcov tool location
+      --ignore-errors ERROR         Continue after ERROR (gcov, source, graph)
+      --no-recursion                Exclude subdirectories from processing
+      --no-markers                  Ignore exclusion markers in source code
+      --derive-func-data            Generate function data from line data
+      --(no-)external               Include (ignore) data for external files
+      --config-file FILENAME        Specify configuration file location
+      --rc SETTING=VALUE            Override configuration file setting
+      --compat MODE=on|off|auto     Set compat MODE (libtool, hammer, split_crc)
+      --include PATTERN             Include files matching PATTERN
+      --exclude PATTERN             Exclude files matching PATTERN
+
+For more information see: $lcov_url
+END_OF_USAGE
+	;
+}
+
+
+#
+# transform_pattern(pattern)
+#
+# Transform shell wildcard expression to equivalent Perl regular expression.
+# Return transformed pattern.
+#
+
+sub transform_pattern($)
+{
+	my $pattern = $_[0];
+
+	# Escape special chars
+
+	$pattern =~ s/\\/\\\\/g;
+	$pattern =~ s/\//\\\//g;
+	$pattern =~ s/\^/\\\^/g;
+	$pattern =~ s/\$/\\\$/g;
+	$pattern =~ s/\(/\\\(/g;
+	$pattern =~ s/\)/\\\)/g;
+	$pattern =~ s/\[/\\\[/g;
+	$pattern =~ s/\]/\\\]/g;
+	$pattern =~ s/\{/\\\{/g;
+	$pattern =~ s/\}/\\\}/g;
+	$pattern =~ s/\./\\\./g;
+	$pattern =~ s/\,/\\\,/g;
+	$pattern =~ s/\|/\\\|/g;
+	$pattern =~ s/\+/\\\+/g;
+	$pattern =~ s/\!/\\\!/g;
+
+	# Transform ? => (.) and * => (.*)
+
+	$pattern =~ s/\*/\(\.\*\)/g;
+	$pattern =~ s/\?/\(\.\)/g;
+
+	return $pattern;
+}
+
+
+#
+# get_common_prefix(min_dir, filenames)
+#
+# Return the longest path prefix shared by all filenames. MIN_DIR specifies
+# the minimum number of directories that a filename may have after removing
+# the prefix.
+#
+
+sub get_common_prefix($@)
+{
+	my ($min_dir, @files) = @_;
+	my $file;
+	my @prefix;
+	my $i;
+
+	foreach $file (@files) {
+		my ($v, $d, $f) = splitpath($file);
+		my @comp = splitdir($d);
+
+		if (!@prefix) {
+			@prefix = @comp;
+			next;
+		}
+		for ($i = 0; $i < scalar(@comp) && $i < scalar(@prefix); $i++) {
+			if ($comp[$i] ne $prefix[$i] ||
+			    ((scalar(@comp) - ($i + 1)) <= $min_dir)) {
+				delete(@prefix[$i..scalar(@prefix)]);
+				last;
+			}
+		}
+	}
+
+	return catdir(@prefix);
+}
+
+#
+# gen_info(directory)
+#
+# Traverse DIRECTORY and create a .info file for each data file found.
+# The .info file contains TEST_NAME in the following format:
+#
+#   TN:<test name>
+#
+# For each source file name referenced in the data file, there is a section
+# containing source code and coverage data:
+#
+#   SF:<absolute path to the source file>
+#   FN:<line number of function start>,<function name> for each function
+#   DA:<line number>,<execution count> for each instrumented line
+#   LH:<number of lines with an execution count> greater than 0
+#   LF:<number of instrumented lines>
+#
+# Sections are separated by:
+#
+#   end_of_record
+#
+# In addition to the main source code file there are sections for each
+# #included file containing executable code. Note that the absolute path
+# of a source file is generated by interpreting the contents of the respective
+# graph file. Relative filenames are prefixed with the directory in which the
+# graph file is found. Note also that symbolic links to the graph file will be
+# resolved so that the actual file path is used instead of the path to a link.
+# This approach is necessary for the mechanism to work with the /proc/gcov
+# files.
+#
+# Die on error.
+#
+
+sub gen_info($)
+{
+	my $directory = $_[0];
+	my @file_list;
+	my $file;
+	my $prefix;
+	my $type;
+	my $ext;
+
+	if ($initial) {
+		$type = "graph";
+		$ext = $graph_file_extension;
+	} else {
+		$type = "data";
+		$ext = $data_file_extension;
+	}
+
+	if (-d $directory)
+	{
+		info("Scanning $directory for $ext files ...\n");
+
+		@file_list = `find "$directory" $maxdepth $follow -name \\*$ext -type f -o -name \\*$ext -type l 2>/dev/null`;
+		chomp(@file_list);
+		if (!@file_list) {
+			warn("WARNING: no $ext files found in $directory - ".
+			     "skipping!\n");
+			return;
+		}
+		$prefix = get_common_prefix(1, @file_list);
+		info("Found %d %s files in %s\n", $#file_list+1, $type,
+		     $directory);
+	}
+	else
+	{
+		@file_list = ($directory);
+		$prefix = "";
+	}
+
+	# Process all files in list
+	foreach $file (@file_list) {
+		# Process file
+		if ($initial) {
+			process_graphfile($file, $prefix);
+		} else {
+			process_dafile($file, $prefix);
+		}
+	}
+
+	# Report whether files were excluded.
+	if (%excluded_files) {
+		info("Excluded data for %d files due to include/exclude options\n",
+			 scalar keys %excluded_files);
+	}
+}
+
+
+#
+# derive_data(contentdata, funcdata, bbdata)
+#
+# Calculate function coverage data by combining line coverage data and the
+# list of lines belonging to a function.
+#
+# contentdata: [ instr1, count1, source1, instr2, count2, source2, ... ]
+# instr<n>: Instrumentation flag for line n
+# count<n>: Execution count for line n
+# source<n>: Source code for line n
+#
+# funcdata: [ count1, func1, count2, func2, ... ]
+# count<n>: Execution count for function number n
+# func<n>: Function name for function number n
+#
+# bbdata: function_name -> [ line1, line2, ... ]
+# line<n>: Line number belonging to the corresponding function
+#
+
+sub derive_data($$$)
+{
+	my ($contentdata, $funcdata, $bbdata) = @_;
+	my @gcov_content = @{$contentdata};
+	my @gcov_functions = @{$funcdata};
+	my %fn_count;
+	my %ln_fn;
+	my $line;
+	my $maxline;
+	my %fn_name;
+	my $fn;
+	my $count;
+
+	if (!defined($bbdata)) {
+		return @gcov_functions;
+	}
+
+	# First add existing function data
+	while (@gcov_functions) {
+		$count = shift(@gcov_functions);
+		$fn = shift(@gcov_functions);
+
+		$fn_count{$fn} = $count;
+	}
+
+	# Convert line coverage data to function data
+	foreach $fn (keys(%{$bbdata})) {
+		my $line_data = $bbdata->{$fn};
+		my $line;
+		my $fninstr = 0;
+
+		if ($fn eq "") {
+			next;
+		}
+		# Find the lowest line count for this function
+		$count = 0;
+		foreach $line (@$line_data) {
+			my $linstr = $gcov_content[ ( $line - 1 ) * 3 + 0 ];
+			my $lcount = $gcov_content[ ( $line - 1 ) * 3 + 1 ];
+
+			next if (!$linstr);
+			$fninstr = 1;
+			if (($lcount > 0) &&
+			    (($count == 0) || ($lcount < $count))) {
+				$count = $lcount;
+			}
+		}
+		next if (!$fninstr);
+		$fn_count{$fn} = $count;
+	}
+
+
+	# Check if we got data for all functions
+	foreach $fn (keys(%fn_name)) {
+		if ($fn eq "") {
+			next;
+		}
+		if (defined($fn_count{$fn})) {
+			next;
+		}
+		warn("WARNING: no derived data found for function $fn\n");
+	}
+
+	# Convert hash to list in @gcov_functions format
+	foreach $fn (sort(keys(%fn_count))) {
+		push(@gcov_functions, $fn_count{$fn}, $fn);
+	}
+
+	return @gcov_functions;
+}
+
+#
+# get_filenames(directory, pattern)
+#
+# Return a list of filenames found in directory which match the specified
+# pattern.
+#
+# Die on error.
+#
+
+sub get_filenames($$)
+{
+	my ($dirname, $pattern) = @_;
+	my @result;
+	my $directory;
+	local *DIR;
+
+	opendir(DIR, $dirname) or
+		die("ERROR: cannot read directory $dirname\n");
+	while ($directory = readdir(DIR)) {
+		push(@result, $directory) if ($directory =~ /$pattern/);
+	}
+	closedir(DIR);
+
+	return @result;
+}
+
+#
+# process_dafile(da_filename, dir)
+#
+# Create a .info file for a single data file.
+#
+# Die on error.
+#
+
+sub process_dafile($$)
+{
+	my ($file, $dir) = @_;
+	my $da_filename;	# Name of data file to process
+	my $da_dir;		# Directory of data file
+	my $source_dir;		# Directory of source file
+	my $da_basename;	# data filename without ".da/.gcda" extension
+	my $bb_filename;	# Name of respective graph file
+	my $bb_basename;	# Basename of the original graph file
+	my $graph;		# Contents of graph file
+	my $instr;		# Contents of graph file part 2
+	my $gcov_error;		# Error code of gcov tool
+	my $object_dir;		# Directory containing all object files
+	my $source_filename;	# Name of a source code file
+	my $gcov_file;		# Name of a .gcov file
+	my @gcov_content;	# Content of a .gcov file
+	my $gcov_branches;	# Branch content of a .gcov file
+	my @gcov_functions;	# Function calls of a .gcov file
+	my @gcov_list;		# List of generated .gcov files
+	my $line_number;	# Line number count
+	my $lines_hit;		# Number of instrumented lines hit
+	my $lines_found;	# Number of instrumented lines found
+	my $funcs_hit;		# Number of instrumented functions hit
+	my $funcs_found;	# Number of instrumented functions found
+	my $br_hit;
+	my $br_found;
+	my $source;		# gcov source header information
+	my $object;		# gcov object header information
+	my @matches;		# List of absolute paths matching filename
+	my $base_dir;		# Base directory for current file
+	my @tmp_links;		# Temporary links to be cleaned up
+	my @result;
+	my $index;
+	my $da_renamed;		# If data file is to be renamed
+	local *INFO_HANDLE;
+
+	info("Processing %s\n", abs2rel($file, $dir));
+	# Get path to data file in absolute and normalized form (begins with /,
+	# contains no more ../ or ./)
+	$da_filename = solve_relative_path($cwd, $file);
+
+	# Get directory and basename of data file
+	($da_dir, $da_basename) = split_filename($da_filename);
+
+	$source_dir = $da_dir;
+	if (is_compat($COMPAT_MODE_LIBTOOL)) {
+		# Avoid files from .libs dirs 	 
+		$source_dir =~ s/\.libs$//;
+	}
+
+	if (-z $da_filename)
+	{
+		$da_renamed = 1;
+	}
+	else
+	{
+		$da_renamed = 0;
+	}
+
+	# Construct base_dir for current file
+	if ($base_directory)
+	{
+		$base_dir = $base_directory;
+	}
+	else
+	{
+		$base_dir = $source_dir;
+	}
+
+	# Check for writable $base_dir (gcov will try to write files there)
+	stat($base_dir);
+	if (!-w _)
+	{
+		die("ERROR: cannot write to directory $base_dir!\n");
+	}
+
+	# Construct name of graph file
+	$bb_basename = $da_basename.$graph_file_extension;
+	$bb_filename = "$da_dir/$bb_basename";
+
+	# Find out the real location of graph file in case we're just looking at
+	# a link
+	while (readlink($bb_filename))
+	{
+		my $last_dir = dirname($bb_filename);
+
+		$bb_filename = readlink($bb_filename);
+		$bb_filename = solve_relative_path($last_dir, $bb_filename);
+	}
+
+	# Ignore empty graph file (e.g. source file with no statement)
+	if (-z $bb_filename)
+	{
+		warn("WARNING: empty $bb_filename (skipped)\n");
+		return;
+	}
+
+	# Read contents of graph file into hash. We need it later to find out
+	# the absolute path to each .gcov file created as well as for
+	# information about functions and their source code positions.
+	if ($gcov_version < $GCOV_VERSION_3_4_0)
+	{
+		if (is_compat($COMPAT_MODE_HAMMER))
+		{
+			($instr, $graph) = read_bbg($bb_filename);
+		}
+		else
+		{
+			($instr, $graph) = read_bb($bb_filename);
+		}
+	} 
+	else
+	{
+		($instr, $graph) = read_gcno($bb_filename);
+	} 
+
+	# Try to find base directory automatically if requested by user
+	if ($rc_auto_base) {
+		$base_dir = find_base_from_graph($base_dir, $instr, $graph);
+	}
+
+	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+
+	# Set $object_dir to real location of object files. This may differ
+	# from $da_dir if the graph file is just a link to the "real" object
+	# file location.
+	$object_dir = dirname($bb_filename);
+
+	# Is the data file in a different directory? (this happens e.g. with
+	# the gcov-kernel patch)
+	if ($object_dir ne $da_dir)
+	{
+		# Need to create link to data file in $object_dir
+		system("ln", "-s", $da_filename, 
+		       "$object_dir/$da_basename$data_file_extension")
+			and die ("ERROR: cannot create link $object_dir/".
+				 "$da_basename$data_file_extension!\n");
+		push(@tmp_links,
+		     "$object_dir/$da_basename$data_file_extension");
+		# Need to create link to graph file if basename of link
+		# and file are different (CONFIG_MODVERSION compat)
+		if ((basename($bb_filename) ne $bb_basename) &&
+		    (! -e "$object_dir/$bb_basename")) {
+			symlink($bb_filename, "$object_dir/$bb_basename") or
+				warn("WARNING: cannot create link ".
+				     "$object_dir/$bb_basename\n");
+			push(@tmp_links, "$object_dir/$bb_basename");
+		}
+	}
+
+	# Change to directory containing data files and apply GCOV
+	debug("chdir($base_dir)\n");
+        chdir($base_dir);
+
+	if ($da_renamed)
+	{
+		# Need to rename empty data file to workaround
+	        # gcov <= 3.2.x bug (Abort)
+		system_no_output(3, "mv", "$da_filename", "$da_filename.ori")
+			and die ("ERROR: cannot rename $da_filename\n");
+	}
+
+	# Execute gcov command and suppress standard output
+	$gcov_error = system_no_output(1, $gcov_tool, $da_filename,
+				       "-o", $object_dir, @gcov_options);
+
+	if ($da_renamed)
+	{
+		system_no_output(3, "mv", "$da_filename.ori", "$da_filename")
+			and die ("ERROR: cannot rename $da_filename.ori");
+	}
+
+	# Clean up temporary links
+	foreach (@tmp_links) {
+		unlink($_);
+	}
+
+	if ($gcov_error)
+	{
+		if ($ignore[$ERROR_GCOV])
+		{
+			warn("WARNING: GCOV failed for $da_filename!\n");
+			return;
+		}
+		die("ERROR: GCOV failed for $da_filename!\n");
+	}
+
+	# Collect data from resulting .gcov files and create .info file
+	@gcov_list = get_filenames('.', '\.gcov$');
+
+	# Check for files
+	if (!@gcov_list)
+	{
+		warn("WARNING: gcov did not create any files for ".
+		     "$da_filename!\n");
+	}
+
+	# Check whether we're writing to a single file
+	if ($output_filename)
+	{
+		if ($output_filename eq "-")
+		{
+			*INFO_HANDLE = *STDOUT;
+		}
+		else
+		{
+			# Append to output file
+			open(INFO_HANDLE, ">>", $output_filename)
+				or die("ERROR: cannot write to ".
+				       "$output_filename!\n");
+		}
+	}
+	else
+	{
+		# Open .info file for output
+		open(INFO_HANDLE, ">", "$da_filename.info")
+			or die("ERROR: cannot create $da_filename.info!\n");
+	}
+
+	# Write test name
+	printf(INFO_HANDLE "TN:%s\n", $test_name);
+
+	# Traverse the list of generated .gcov files and combine them into a
+	# single .info file
+	foreach $gcov_file (sort(@gcov_list))
+	{
+		my $i;
+		my $num;
+
+		# Skip gcov file for gcc built-in code
+		next if ($gcov_file eq "<built-in>.gcov");
+
+		($source, $object) = read_gcov_header($gcov_file);
+
+		if (!defined($source)) {
+			# Derive source file name from gcov file name if
+			# header format could not be parsed
+			$source = $gcov_file;
+			$source =~ s/\.gcov$//;
+		}
+
+		$source = solve_relative_path($base_dir, $source);
+
+		if (defined($adjust_src_pattern)) {
+			# Apply transformation as specified by user
+			$source =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+		}
+
+		# gcov will happily create output even if there's no source code
+		# available - this interferes with checksum creation so we need
+		# to pull the emergency brake here.
+		if (! -r $source && $checksum)
+		{
+			if ($ignore[$ERROR_SOURCE])
+			{
+				warn("WARNING: could not read source file ".
+				     "$source\n");
+				next;
+			}
+			die("ERROR: could not read source file $source\n");
+		}
+
+		@matches = match_filename($source, keys(%{$instr}));
+
+		# Skip files that are not mentioned in the graph file
+		if (!@matches)
+		{
+			warn("WARNING: cannot find an entry for ".$gcov_file.
+			     " in $graph_file_extension file, skipping ".
+			     "file!\n");
+			unlink($gcov_file);
+			next;
+		}
+
+		# Read in contents of gcov file
+		@result = read_gcov_file($gcov_file);
+		if (!defined($result[0])) {
+			warn("WARNING: skipping unreadable file ".
+			     $gcov_file."\n");
+			unlink($gcov_file);
+			next;
+		}
+		@gcov_content = @{$result[0]};
+		$gcov_branches = $result[1];
+		@gcov_functions = @{$result[2]};
+
+		# Skip empty files
+		if (!@gcov_content)
+		{
+			warn("WARNING: skipping empty file ".$gcov_file."\n");
+			unlink($gcov_file);
+			next;
+		}
+
+		if (scalar(@matches) == 1)
+		{
+			# Just one match
+			$source_filename = $matches[0];
+		}
+		else
+		{
+			# Try to solve the ambiguity
+			$source_filename = solve_ambiguous_match($gcov_file,
+						\@matches, \@gcov_content);
+		}
+
+		if (@include_patterns)
+		{
+			my $keep = 0;
+
+			foreach my $pattern (@include_patterns)
+			{
+				$keep ||= ($source_filename =~ (/^$pattern$/));
+			}
+
+			if (!$keep)
+			{
+				$excluded_files{$source_filename} = ();
+				unlink($gcov_file);
+				next;
+			}
+		}
+
+		if (@exclude_patterns)
+		{
+			my $exclude = 0;
+
+			foreach my $pattern (@exclude_patterns)
+			{
+				$exclude ||= ($source_filename =~ (/^$pattern$/));
+			}
+
+			if ($exclude)
+			{
+				$excluded_files{$source_filename} = ();
+				unlink($gcov_file);
+				next;
+			}
+		}
+
+		# Skip external files if requested
+		if (!$opt_external) {
+			if (is_external($source_filename)) {
+				info("  ignoring data for external file ".
+				     "$source_filename\n");
+				unlink($gcov_file);
+				next;
+			}
+		}
+
+		# Write absolute path of source file
+		printf(INFO_HANDLE "SF:%s\n", $source_filename);
+
+		# If requested, derive function coverage data from
+		# line coverage data of the first line of a function
+		if ($opt_derive_func_data) {
+			@gcov_functions =
+				derive_data(\@gcov_content, \@gcov_functions,
+					    $graph->{$source_filename});
+		}
+
+		# Write function-related information
+		if (defined($graph->{$source_filename}))
+		{
+			my $fn_data = $graph->{$source_filename};
+			my $fn;
+
+			foreach $fn (sort
+				{$fn_data->{$a}->[0] <=> $fn_data->{$b}->[0]}
+				keys(%{$fn_data})) {
+				my $ln_data = $fn_data->{$fn};
+				my $line = $ln_data->[0];
+
+				# Skip empty function
+				if ($fn eq "") {
+					next;
+				}
+				# Remove excluded functions
+				if (!$no_markers) {
+					my $gfn;
+					my $found = 0;
+
+					foreach $gfn (@gcov_functions) {
+						if ($gfn eq $fn) {
+							$found = 1;
+							last;
+						}
+					}
+					if (!$found) {
+						next;
+					}
+				}
+
+				# Normalize function name
+				$fn = filter_fn_name($fn);
+
+				print(INFO_HANDLE "FN:$line,$fn\n");
+			}
+		}
+
+		#--
+		#-- FNDA: <call-count>, <function-name>
+		#-- FNF: overall count of functions
+		#-- FNH: overall count of functions with non-zero call count
+		#--
+		$funcs_found = 0;
+		$funcs_hit = 0;
+		while (@gcov_functions)
+		{
+			my $count = shift(@gcov_functions);
+			my $fn = shift(@gcov_functions);
+
+			$fn = filter_fn_name($fn);
+			printf(INFO_HANDLE "FNDA:$count,$fn\n");
+			$funcs_found++;
+			$funcs_hit++ if ($count > 0);
+		}
+		if ($funcs_found > 0) {
+			printf(INFO_HANDLE "FNF:%s\n", $funcs_found);
+			printf(INFO_HANDLE "FNH:%s\n", $funcs_hit);
+		}
+
+		# Write coverage information for each instrumented branch:
+		#
+		#   BRDA:<line number>,<block number>,<branch number>,<taken>
+		#
+		# where 'taken' is the number of times the branch was taken
+		# or '-' if the block to which the branch belongs was never
+		# executed
+		$br_found = 0;
+		$br_hit = 0;
+		$num = br_gvec_len($gcov_branches);
+		for ($i = 0; $i < $num; $i++) {
+			my ($line, $block, $branch, $taken) =
+				br_gvec_get($gcov_branches, $i);
+
+			$block = $BR_VEC_MAX if ($block < 0);
+			print(INFO_HANDLE "BRDA:$line,$block,$branch,$taken\n");
+			$br_found++;
+			$br_hit++ if ($taken ne '-' && $taken > 0);
+		}
+		if ($br_found > 0) {
+			printf(INFO_HANDLE "BRF:%s\n", $br_found);
+			printf(INFO_HANDLE "BRH:%s\n", $br_hit);
+		}
+
+		# Reset line counters
+		$line_number = 0;
+		$lines_found = 0;
+		$lines_hit = 0;
+
+		# Write coverage information for each instrumented line
+		# Note: @gcov_content contains a list of (flag, count, source)
+		# tuple for each source code line
+		while (@gcov_content)
+		{
+			$line_number++;
+
+			# Check for instrumented line
+			if ($gcov_content[0])
+			{
+				$lines_found++;
+				printf(INFO_HANDLE "DA:".$line_number.",".
+				       $gcov_content[1].($checksum ?
+				       ",". md5_base64($gcov_content[2]) : "").
+				       "\n");
+
+				# Increase $lines_hit in case of an execution
+				# count>0
+				if ($gcov_content[1] > 0) { $lines_hit++; }
+			}
+
+			# Remove already processed data from array
+			splice(@gcov_content,0,3);
+		}
+
+		# Write line statistics and section separator
+		printf(INFO_HANDLE "LF:%s\n", $lines_found);
+		printf(INFO_HANDLE "LH:%s\n", $lines_hit);
+		print(INFO_HANDLE "end_of_record\n");
+
+		# Remove .gcov file after processing
+		unlink($gcov_file);
+	}
+
+	if (!($output_filename && ($output_filename eq "-")))
+	{
+		close(INFO_HANDLE);
+	}
+
+	# Change back to initial directory
+	chdir($cwd);
+}
+
+
+#
+# solve_relative_path(path, dir)
+#
+# Solve relative path components of DIR which, if not absolute, resides in PATH.
+#
+
+sub solve_relative_path($$)
+{
+	my $path = $_[0];
+	my $dir = $_[1];
+	my $volume;
+	my $directories;
+	my $filename;
+	my @dirs;			# holds path elements
+	my $result;
+
+	# Convert from Windows path to msys path
+	if( $^O eq "msys" )
+	{
+		# search for a windows drive letter at the beginning
+		($volume, $directories, $filename) = File::Spec::Win32->splitpath( $dir );
+		if( $volume ne '' )
+		{
+			my $uppercase_volume;
+			# transform c/d\../e/f\g to Windows style c\d\..\e\f\g
+			$dir = File::Spec::Win32->canonpath( $dir );
+			# use Win32 module to retrieve path components
+			# $uppercase_volume is not used any further
+			( $uppercase_volume, $directories, $filename ) = File::Spec::Win32->splitpath( $dir );
+			@dirs = File::Spec::Win32->splitdir( $directories );
+			
+			# prepend volume, since in msys C: is always mounted to /c
+			$volume =~ s|^([a-zA-Z]+):|/\L$1\E|;
+			unshift( @dirs, $volume );
+			
+			# transform to Unix style '/' path
+			$directories = File::Spec->catdir( @dirs );
+			$dir = File::Spec->catpath( '', $directories, $filename );
+		} else {
+			# eliminate '\' path separators
+			$dir = File::Spec->canonpath( $dir );
+		}
+	}
+
+	$result = $dir;
+	# Prepend path if not absolute
+	if ($dir =~ /^[^\/]/)
+	{
+		$result = "$path/$result";
+	}
+
+	# Remove //
+	$result =~ s/\/\//\//g;
+
+	# Remove .
+	while ($result =~ s/\/\.\//\//g)
+	{
+	}
+	$result =~ s/\/\.$/\//g;
+
+	# Remove trailing /
+	$result =~ s/\/$//g;
+
+	# Solve ..
+	while ($result =~ s/\/[^\/]+\/\.\.\//\//)
+	{
+	}
+
+	# Remove preceding ..
+	$result =~ s/^\/\.\.\//\//g;
+
+	return $result;
+}
+
+
+#
+# match_filename(gcov_filename, list)
+#
+# Return a list of those entries of LIST which match the relative filename
+# GCOV_FILENAME.
+#
+
+sub match_filename($@)
+{
+	my ($filename, @list) = @_;
+	my ($vol, $dir, $file) = splitpath($filename);
+	my @comp = splitdir($dir);
+	my $comps = scalar(@comp);
+	my $entry;
+	my @result;
+
+entry:
+	foreach $entry (@list) {
+		my ($evol, $edir, $efile) = splitpath($entry);
+		my @ecomp;
+		my $ecomps;
+		my $i;
+
+		# Filename component must match
+		if ($efile ne $file) {
+			next;
+		}
+		# Check directory components last to first for match
+		@ecomp = splitdir($edir);
+		$ecomps = scalar(@ecomp);
+		if ($ecomps < $comps) {
+			next;
+		}
+		for ($i = 0; $i < $comps; $i++) {
+			if ($comp[$comps - $i - 1] ne
+			    $ecomp[$ecomps - $i - 1]) {
+				next entry;
+			}
+		}
+		push(@result, $entry),
+	}
+
+	return @result;
+}
+
+#
+# solve_ambiguous_match(rel_filename, matches_ref, gcov_content_ref)
+#
+# Try to solve ambiguous matches of mapping (gcov file) -> (source code) file
+# by comparing source code provided in the GCOV file with that of the files
+# in MATCHES. REL_FILENAME identifies the relative filename of the gcov
+# file.
+# 
+# Return the one real match or die if there is none.
+#
+
+sub solve_ambiguous_match($$$)
+{
+	my $rel_name = $_[0];
+	my $matches = $_[1];
+	my $content = $_[2];
+	my $filename;
+	my $index;
+	my $no_match;
+	local *SOURCE;
+
+	# Check the list of matches
+	foreach $filename (@$matches)
+	{
+
+		# Compare file contents
+		open(SOURCE, "<", $filename)
+			or die("ERROR: cannot read $filename!\n");
+
+		$no_match = 0;
+		for ($index = 2; <SOURCE>; $index += 3)
+		{
+			chomp;
+
+			# Also remove CR from line-end
+			s/\015$//;
+
+			if ($_ ne @$content[$index])
+			{
+				$no_match = 1;
+				last;
+			}
+		}
+
+		close(SOURCE);
+
+		if (!$no_match)
+		{
+			info("Solved source file ambiguity for $rel_name\n");
+			return $filename;
+		}
+	}
+
+	die("ERROR: could not match gcov data for $rel_name!\n");
+}
+
+
+#
+# split_filename(filename)
+#
+# Return (path, filename, extension) for a given FILENAME.
+#
+
+sub split_filename($)
+{
+	my @path_components = split('/', $_[0]);
+	my @file_components = split('\.', pop(@path_components));
+	my $extension = pop(@file_components);
+
+	return (join("/",@path_components), join(".",@file_components),
+		$extension);
+}
+
+
+#
+# read_gcov_header(gcov_filename)
+#
+# Parse file GCOV_FILENAME and return a list containing the following
+# information:
+#
+#   (source, object)
+#
+# where:
+#
+# source: complete relative path of the source code file (gcc >= 3.3 only)
+# object: name of associated graph file
+#
+# Die on error.
+#
+
+sub read_gcov_header($)
+{
+	my $source;
+	my $object;
+	local *INPUT;
+
+	if (!open(INPUT, "<", $_[0]))
+	{
+		if ($ignore_errors[$ERROR_GCOV])
+		{
+			warn("WARNING: cannot read $_[0]!\n");
+			return (undef,undef);
+		}
+		die("ERROR: cannot read $_[0]!\n");
+	}
+
+	while (<INPUT>)
+	{
+		chomp($_);
+
+		# Also remove CR from line-end
+		s/\015$//;
+
+		if (/^\s+-:\s+0:Source:(.*)$/)
+		{
+			# Source: header entry
+			$source = $1;
+		}
+		elsif (/^\s+-:\s+0:Object:(.*)$/)
+		{
+			# Object: header entry
+			$object = $1;
+		}
+		else
+		{
+			last;
+		}
+	}
+
+	close(INPUT);
+
+	return ($source, $object);
+}
+
+
+#
+# br_gvec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_gvec_len($)
+{
+	my ($vec) = @_;
+
+	return 0 if (!defined($vec));
+	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_gvec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_gvec_get($$)
+{
+	my ($vec, $num) = @_;
+	my $line;
+	my $block;
+	my $branch;
+	my $taken;
+	my $offset = $num * $BR_VEC_ENTRIES;
+
+	# Retrieve data from vector
+	$line	= vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH);
+	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+	$block = -1 if ($block == $BR_VEC_MAX);
+	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+	# Decode taken value from an integer
+	if ($taken == 0) {
+		$taken = "-";
+	} else {
+		$taken--;
+	}
+
+	return ($line, $block, $branch, $taken);
+}
+
+
+#
+# br_gvec_push(vector, line, block, branch, taken)
+#
+# Add an entry to the branch coverage vector.
+#
+
+sub br_gvec_push($$$$$)
+{
+	my ($vec, $line, $block, $branch, $taken) = @_;
+	my $offset;
+
+	$vec = "" if (!defined($vec));
+	$offset = br_gvec_len($vec) * $BR_VEC_ENTRIES;
+	$block = $BR_VEC_MAX if $block < 0;
+
+	# Encode taken value into an integer
+	if ($taken eq "-") {
+		$taken = 0;
+	} else {
+		$taken++;
+	}
+
+	# Add to vector
+	vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH) = $line;
+	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+	return $vec;
+}
+
+
+#
+# read_gcov_file(gcov_filename)
+#
+# Parse file GCOV_FILENAME (.gcov file format) and return the list:
+# (reference to gcov_content, reference to gcov_branch, reference to gcov_func)
+#
+# gcov_content is a list of 3 elements
+# (flag, count, source) for each source code line:
+#
+# $result[($line_number-1)*3+0] = instrumentation flag for line $line_number
+# $result[($line_number-1)*3+1] = execution count for line $line_number
+# $result[($line_number-1)*3+2] = source code text for line $line_number
+#
+# gcov_branch is a vector of 4 4-byte long elements for each branch:
+# line number, block number, branch number, count + 1 or 0
+#
+# gcov_func is a list of 2 elements
+# (number of calls, function name) for each function
+#
+# Die on error.
+#
+
+sub read_gcov_file($)
+{
+	my $filename = $_[0];
+	my @result = ();
+	my $branches = "";
+	my @functions = ();
+	my $number;
+	my $exclude_flag = 0;
+	my $exclude_line = 0;
+	my $exclude_br_flag = 0;
+	my $exclude_branch = 0;
+	my $last_block = $UNNAMED_BLOCK;
+	my $last_line = 0;
+	local *INPUT;
+
+	if (!open(INPUT, "<", $filename)) {
+		if ($ignore_errors[$ERROR_GCOV])
+		{
+			warn("WARNING: cannot read $filename!\n");
+			return (undef, undef, undef);
+		}
+		die("ERROR: cannot read $filename!\n");
+	}
+
+	if ($gcov_version < $GCOV_VERSION_3_3_0)
+	{
+		# Expect gcov format as used in gcc < 3.3
+		while (<INPUT>)
+		{
+			chomp($_);
+
+			# Also remove CR from line-end
+			s/\015$//;
+
+			if (/^branch\s+(\d+)\s+taken\s+=\s+(\d+)/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				next if ($exclude_branch);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, $2);
+			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				next if ($exclude_branch);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, '-');
+			}
+			elsif (/^call/ || /^function/)
+			{
+				# Function call return data
+			}
+			else
+			{
+				$last_line++;
+				# Check for exclusion markers
+				if (!$no_markers) {
+					if (/$EXCL_STOP/) {
+						$exclude_flag = 0;
+					} elsif (/$EXCL_START/) {
+						$exclude_flag = 1;
+					}
+					if (/$excl_line/ || $exclude_flag) {
+						$exclude_line = 1;
+					} else {
+						$exclude_line = 0;
+					}
+				}
+				# Check for exclusion markers (branch exclude)
+				if (!$no_markers) {
+					if (/$EXCL_BR_STOP/) {
+						$exclude_br_flag = 0;
+					} elsif (/$EXCL_BR_START/) {
+						$exclude_br_flag = 1;
+					}
+					if (/$excl_br_line/ || $exclude_br_flag) {
+						$exclude_branch = 1;
+					} else {
+						$exclude_branch = 0;
+					}
+				}
+				# Source code execution data
+				if (/^\t\t(.*)$/)
+				{
+					# Uninstrumented line
+					push(@result, 0);
+					push(@result, 0);
+					push(@result, $1);
+					next;
+				}
+				$number = (split(" ",substr($_, 0, 16)))[0];
+
+				# Check for zero count which is indicated
+				# by ######
+				if ($number eq "######") { $number = 0;	}
+
+				if ($exclude_line) {
+					# Register uninstrumented line instead
+					push(@result, 0);
+					push(@result, 0);
+				} else {
+					push(@result, 1);
+					push(@result, $number);
+				}
+				push(@result, substr($_, 16));
+			}
+		}
+	}
+	else
+	{
+		# Expect gcov format as used in gcc >= 3.3
+		while (<INPUT>)
+		{
+			chomp($_);
+
+			# Also remove CR from line-end
+			s/\015$//;
+
+			if (/^\s*(\d+|\$+|\%+):\s*(\d+)-block\s+(\d+)\s*$/) {
+				# Block information - used to group related
+				# branches
+				$last_line = $2;
+				$last_block = $3;
+			} elsif (/^branch\s+(\d+)\s+taken\s+(\d+)/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				next if ($exclude_branch);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, $2);
+			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				next if ($exclude_branch);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, '-');
+			}
+			elsif (/^function\s+(.+)\s+called\s+(\d+)\s+/)
+			{
+				next if (!$func_coverage);
+				if ($exclude_line) {
+					next;
+				}
+				push(@functions, $2, $1);
+			}
+			elsif (/^call/)
+			{
+				# Function call return data
+			}
+			elsif (/^\s*([^:]+):\s*([^:]+):(.*)$/)
+			{
+				my ($count, $line, $code) = ($1, $2, $3);
+
+				# Skip instance-specific counts
+				next if ($line <= (scalar(@result) / 3));
+
+				$last_line = $line;
+				$last_block = $UNNAMED_BLOCK;
+				# Check for exclusion markers
+				if (!$no_markers) {
+					if (/$EXCL_STOP/) {
+						$exclude_flag = 0;
+					} elsif (/$EXCL_START/) {
+						$exclude_flag = 1;
+					}
+					if (/$excl_line/ || $exclude_flag) {
+						$exclude_line = 1;
+					} else {
+						$exclude_line = 0;
+					}
+				}
+				# Check for exclusion markers (branch exclude)
+				if (!$no_markers) {
+					if (/$EXCL_BR_STOP/) {
+						$exclude_br_flag = 0;
+					} elsif (/$EXCL_BR_START/) {
+						$exclude_br_flag = 1;
+					}
+					if (/$excl_br_line/ || $exclude_br_flag) {
+						$exclude_branch = 1;
+					} else {
+						$exclude_branch = 0;
+					}
+				}
+
+				# Strip unexecuted basic block marker
+				$count =~ s/\*$//;
+
+				# <exec count>:<line number>:<source code>
+				if ($line eq "0")
+				{
+					# Extra data
+				}
+				elsif ($count eq "-")
+				{
+					# Uninstrumented line
+					push(@result, 0);
+					push(@result, 0);
+					push(@result, $code);
+				}
+				else
+				{
+					if ($exclude_line) {
+						push(@result, 0);
+						push(@result, 0);
+					} else {
+						# Check for zero count
+						if ($count =~ /^[#=]/) {
+							$count = 0;
+						}
+						push(@result, 1);
+						push(@result, $count);
+					}
+					push(@result, $code);
+				}
+			}
+		}
+	}
+
+	close(INPUT);
+	if ($exclude_flag || $exclude_br_flag) {
+		warn("WARNING: unterminated exclusion section in $filename\n");
+	}
+	return(\@result, $branches, \@functions);
+}
+
+
+# Map LLVM versions to the version of GCC gcov which they emulate.
+
+sub map_llvm_version($)
+{
+	my ($ver) = @_;
+
+	return 0x040200 if ($ver >= 0x030400);
+
+	warn("WARNING: This version of LLVM's gcov is unknown.  ".
+	     "Assuming it emulates GCC gcov version 4.2.\n");
+
+	return 0x040200;
+}
+
+
+# Return a readable version of encoded gcov version.
+
+sub version_to_str($)
+{
+	my ($ver) = @_;
+	my ($a, $b, $c);
+
+	$a = $ver >> 16 & 0xff;
+	$b = $ver >> 8 & 0xff;
+	$c = $ver & 0xff;
+
+	return "$a.$b.$c";
+}
+
+
+#
+# Get the GCOV tool version. Return an integer number which represents the
+# GCOV version. Version numbers can be compared using standard integer
+# operations.
+#
+
+sub get_gcov_version()
+{
+	local *HANDLE;
+	my $version_string;
+	my $result;
+	my ($a, $b, $c) = (4, 2, 0);	# Fallback version
+
+	# Examples for gcov version output:
+	#
+	# gcov (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)
+	#
+	# gcov (crosstool-NG 1.18.0) 4.7.2
+	#
+	# LLVM (http://llvm.org/):
+	#   LLVM version 3.4svn
+	#
+	# Apple LLVM version 8.0.0 (clang-800.0.38)
+	#       Optimized build.
+	#       Default target: x86_64-apple-darwin16.0.0
+	#       Host CPU: haswell
+
+	open(GCOV_PIPE, "-|", "$gcov_tool --version")
+		or die("ERROR: cannot retrieve gcov version!\n");
+	local $/;
+	$version_string = <GCOV_PIPE>;
+	close(GCOV_PIPE);
+
+	# Remove all bracketed information
+	$version_string =~ s/\([^\)]*\)//g;
+
+	if ($version_string =~ /(\d+)\.(\d+)(\.(\d+))?/) {
+		($a, $b, $c) = ($1, $2, $4);
+		$c = 0 if (!defined($c));
+	} else {
+		warn("WARNING: cannot determine gcov version - ".
+		     "assuming $a.$b.$c\n");
+	}
+	$result = $a << 16 | $b << 8 | $c;
+
+	if ($version_string =~ /LLVM/) {
+		$result = map_llvm_version($result);
+		info("Found LLVM gcov version $a.$b.$c, which emulates gcov ".
+		     "version ".version_to_str($result)."\n");
+	} else {
+		info("Found gcov version: ".version_to_str($result)."\n");
+	}
+
+	return ($result, $version_string);
+}
+
+
+#
+# info(printf_parameter)
+#
+# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
+# is not set.
+#
+
+sub info(@)
+{
+	if (!$quiet)
+	{
+		# Print info string
+		if (defined($output_filename) && ($output_filename eq "-"))
+		{
+			# Don't interfere with the .info output to STDOUT
+			printf(STDERR @_);
+		}
+		else
+		{
+			printf(@_);
+		}
+	}
+}
+
+
+#
+# int_handler()
+#
+# Called when the script was interrupted by an INT signal (e.g. CTRl-C)
+#
+
+sub int_handler()
+{
+	if ($cwd) { chdir($cwd); }
+	info("Aborted.\n");
+	exit(1);
+}
+
+
+#
+# system_no_output(mode, parameters)
+#
+# Call an external program using PARAMETERS while suppressing depending on
+# the value of MODE:
+#
+#   MODE & 1: suppress STDOUT
+#   MODE & 2: suppress STDERR
+#
+# Return 0 on success, non-zero otherwise.
+#
+
+sub system_no_output($@)
+{
+	my $mode = shift;
+	my $result;
+	local *OLD_STDERR;
+	local *OLD_STDOUT;
+
+	# Save old stdout and stderr handles
+	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
+
+	# Redirect to /dev/null
+	($mode & 1) && open(STDOUT, ">", "/dev/null");
+	($mode & 2) && open(STDERR, ">", "/dev/null");
+ 
+	debug("system(".join(' ', @_).")\n");
+	system(@_);
+	$result = $?;
+
+	# Close redirected handles
+	($mode & 1) && close(STDOUT);
+	($mode & 2) && close(STDERR);
+
+	# Restore old handles
+	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
+ 
+	return $result;
+}
+
+
+#
+# read_config(filename)
+#
+# Read configuration file FILENAME and return a reference to a hash containing
+# all valid key=value pairs found.
+#
+
+sub read_config($)
+{
+	my $filename = $_[0];
+	my %result;
+	my $key;
+	my $value;
+	local *HANDLE;
+
+	if (!open(HANDLE, "<", $filename))
+	{
+		warn("WARNING: cannot read configuration file $filename\n");
+		return undef;
+	}
+	while (<HANDLE>)
+	{
+		chomp;
+		# Skip comments
+		s/#.*//;
+		# Remove leading blanks
+		s/^\s+//;
+		# Remove trailing blanks
+		s/\s+$//;
+		next unless length;
+		($key, $value) = split(/\s*=\s*/, $_, 2);
+		if (defined($key) && defined($value))
+		{
+			$result{$key} = $value;
+		}
+		else
+		{
+			warn("WARNING: malformed statement in line $. ".
+			     "of configuration file $filename\n");
+		}
+	}
+	close(HANDLE);
+	return \%result;
+}
+
+
+#
+# apply_config(REF)
+#
+# REF is a reference to a hash containing the following mapping:
+#
+#   key_string => var_ref
+#
+# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
+#
+
+sub apply_config($)
+{
+	my $ref = $_[0];
+
+	foreach (keys(%{$ref}))
+	{
+		if (defined($opt_rc{$_})) {
+			${$ref->{$_}} = $opt_rc{$_};
+		} elsif (defined($config->{$_})) {
+			${$ref->{$_}} = $config->{$_};
+		}
+	}
+}
+
+
+#
+# get_exclusion_data(filename)
+#
+# Scan specified source code file for exclusion markers and return
+#   linenumber -> 1
+# for all lines which should be excluded.
+#
+
+sub get_exclusion_data($)
+{
+	my ($filename) = @_;
+	my %list;
+	my $flag = 0;
+	local *HANDLE;
+
+	if (!open(HANDLE, "<", $filename)) {
+		warn("WARNING: could not open $filename\n");
+		return undef;
+	}
+	while (<HANDLE>) {
+		if (/$EXCL_STOP/) {
+			$flag = 0;
+		} elsif (/$EXCL_START/) {
+			$flag = 1;
+		}
+		if (/$excl_line/ || $flag) {
+			$list{$.} = 1;
+		}
+	}
+	close(HANDLE);
+
+	if ($flag) {
+		warn("WARNING: unterminated exclusion section in $filename\n");
+	}
+
+	return \%list;
+}
+
+
+#
+# apply_exclusion_data(instr, graph)
+#
+# Remove lines from instr and graph data structures which are marked
+# for exclusion in the source code file.
+#
+# Return adjusted (instr, graph).
+#
+# graph         : file name -> function data
+# function data : function name -> line data
+# line data     : [ line1, line2, ... ]
+#
+# instr     : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+
+sub apply_exclusion_data($$)
+{
+	my ($instr, $graph) = @_;
+	my $filename;
+	my %excl_data;
+	my $excl_read_failed = 0;
+
+	# Collect exclusion marker data
+	foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {
+		my $excl = get_exclusion_data($filename);
+
+		# Skip and note if file could not be read
+		if (!defined($excl)) {
+			$excl_read_failed = 1;
+			next;
+		}
+
+		# Add to collection if there are markers
+		$excl_data{$filename} = $excl if (keys(%{$excl}) > 0);
+	}
+
+	# Warn if not all source files could be read
+	if ($excl_read_failed) {
+		warn("WARNING: some exclusion markers may be ignored\n");
+	}
+
+	# Skip if no markers were found
+	return ($instr, $graph) if (keys(%excl_data) == 0);
+
+	# Apply exclusion marker data to graph
+	foreach $filename (keys(%excl_data)) {
+		my $function_data = $graph->{$filename};
+		my $excl = $excl_data{$filename};
+		my $function;
+
+		next if (!defined($function_data));
+
+		foreach $function (keys(%{$function_data})) {
+			my $line_data = $function_data->{$function};
+			my $line;
+			my @new_data;
+
+			# To be consistent with exclusion parser in non-initial
+			# case we need to remove a function if the first line
+			# was excluded
+			if ($excl->{$line_data->[0]}) {
+				delete($function_data->{$function});
+				next;
+			}
+			# Copy only lines which are not excluded
+			foreach $line (@{$line_data}) {
+				push(@new_data, $line) if (!$excl->{$line});
+			}
+
+			# Store modified list
+			if (scalar(@new_data) > 0) {
+				$function_data->{$function} = \@new_data;
+			} else {
+				# All of this function was excluded
+				delete($function_data->{$function});
+			}
+		}
+
+		# Check if all functions of this file were excluded
+		if (keys(%{$function_data}) == 0) {
+			delete($graph->{$filename});
+		}
+	}
+
+	# Apply exclusion marker data to instr
+	foreach $filename (keys(%excl_data)) {
+		my $line_data = $instr->{$filename};
+		my $excl = $excl_data{$filename};
+		my $line;
+		my @new_data;
+
+		next if (!defined($line_data));
+
+		# Copy only lines which are not excluded
+		foreach $line (@{$line_data}) {
+			push(@new_data, $line) if (!$excl->{$line});
+		}
+
+		# Store modified list
+		$instr->{$filename} = \@new_data;
+	}
+
+	return ($instr, $graph);
+}
+
+
+sub process_graphfile($$)
+{
+	my ($file, $dir) = @_;
+	my $graph_filename = $file;
+	my $graph_dir;
+	my $graph_basename;
+	my $source_dir;
+	my $base_dir;
+	my $graph;
+	my $instr;
+	my $filename;
+	local *INFO_HANDLE;
+
+	info("Processing %s\n", abs2rel($file, $dir));
+
+	# Get path to data file in absolute and normalized form (begins with /,
+	# contains no more ../ or ./)
+	$graph_filename = solve_relative_path($cwd, $graph_filename);
+
+	# Get directory and basename of data file
+	($graph_dir, $graph_basename) = split_filename($graph_filename);
+
+	$source_dir = $graph_dir;
+	if (is_compat($COMPAT_MODE_LIBTOOL)) {
+		# Avoid files from .libs dirs 	 
+		$source_dir =~ s/\.libs$//;
+	}
+
+	# Construct base_dir for current file
+	if ($base_directory)
+	{
+		$base_dir = $base_directory;
+	}
+	else
+	{
+		$base_dir = $source_dir;
+	}
+
+	# Ignore empty graph file (e.g. source file with no statement)
+	if (-z $graph_filename)
+	{
+		warn("WARNING: empty $graph_filename (skipped)\n");
+		return;
+	}
+
+	if ($gcov_version < $GCOV_VERSION_3_4_0)
+	{
+		if (is_compat($COMPAT_MODE_HAMMER))
+		{
+			($instr, $graph) = read_bbg($graph_filename);
+		}
+		else
+		{
+			($instr, $graph) = read_bb($graph_filename);
+		}
+	} 
+	else
+	{
+		($instr, $graph) = read_gcno($graph_filename);
+	}
+
+	# Try to find base directory automatically if requested by user
+	if ($rc_auto_base) {
+		$base_dir = find_base_from_graph($base_dir, $instr, $graph);
+	}
+
+	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+
+	if (!$no_markers) {
+		# Apply exclusion marker data to graph file data
+		($instr, $graph) = apply_exclusion_data($instr, $graph);
+	}
+
+	# Check whether we're writing to a single file
+	if ($output_filename)
+	{
+		if ($output_filename eq "-")
+		{
+			*INFO_HANDLE = *STDOUT;
+		}
+		else
+		{
+			# Append to output file
+			open(INFO_HANDLE, ">>", $output_filename)
+				or die("ERROR: cannot write to ".
+				       "$output_filename!\n");
+		}
+	}
+	else
+	{
+		# Open .info file for output
+		open(INFO_HANDLE, ">", "$graph_filename.info")
+			or die("ERROR: cannot create $graph_filename.info!\n");
+	}
+
+	# Write test name
+	printf(INFO_HANDLE "TN:%s\n", $test_name);
+	foreach $filename (sort(keys(%{$instr})))
+	{
+		my $funcdata = $graph->{$filename};
+		my $line;
+		my $linedata;
+
+		# Skip external files if requested
+		if (!$opt_external) {
+			if (is_external($filename)) {
+				info("  ignoring data for external file ".
+				     "$filename\n");
+				next;
+			}
+		}
+
+		print(INFO_HANDLE "SF:$filename\n");
+
+		if (defined($funcdata) && $func_coverage) {
+			my @functions = sort {$funcdata->{$a}->[0] <=>
+					      $funcdata->{$b}->[0]}
+					     keys(%{$funcdata});
+			my $func;
+
+			# Gather list of instrumented lines and functions
+			foreach $func (@functions) {
+				$linedata = $funcdata->{$func};
+
+				# Print function name and starting line
+				print(INFO_HANDLE "FN:".$linedata->[0].
+				      ",".filter_fn_name($func)."\n");
+			}
+			# Print zero function coverage data
+			foreach $func (@functions) {
+				print(INFO_HANDLE "FNDA:0,".
+				      filter_fn_name($func)."\n");
+			}
+			# Print function summary
+			print(INFO_HANDLE "FNF:".scalar(@functions)."\n");
+			print(INFO_HANDLE "FNH:0\n");
+		}
+		# Print zero line coverage data
+		foreach $line (@{$instr->{$filename}}) {
+			print(INFO_HANDLE "DA:$line,0\n");
+		}
+		# Print line summary
+		print(INFO_HANDLE "LF:".scalar(@{$instr->{$filename}})."\n");
+		print(INFO_HANDLE "LH:0\n");
+
+		print(INFO_HANDLE "end_of_record\n");
+	}
+	if (!($output_filename && ($output_filename eq "-")))
+	{
+		close(INFO_HANDLE);
+	}
+}
+
+sub filter_fn_name($)
+{
+	my ($fn) = @_;
+
+	# Remove characters used internally as function name delimiters
+	$fn =~ s/[,=]/_/g;
+
+	return $fn;
+}
+
+sub warn_handler($)
+{
+	my ($msg) = @_;
+
+	warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+	my ($msg) = @_;
+
+	die("$tool_name: $msg");
+}
+
+
+#
+# graph_error(filename, message)
+#
+# Print message about error in graph file. If ignore_graph_error is set, return.
+# Otherwise abort.
+#
+
+sub graph_error($$)
+{
+	my ($filename, $msg) = @_;
+
+	if ($ignore[$ERROR_GRAPH]) {
+		warn("WARNING: $filename: $msg - skipping\n");
+		return;
+	}
+	die("ERROR: $filename: $msg\n");
+}
+
+#
+# graph_expect(description)
+#
+# If debug is set to a non-zero value, print the specified description of what
+# is expected to be read next from the graph file.
+#
+
+sub graph_expect($)
+{
+	my ($msg) = @_;
+
+	if (!$debug || !defined($msg)) {
+		return;
+	}
+
+	print(STDERR "DEBUG: expecting $msg\n");
+}
+
+#
+# graph_read(handle, bytes[, description, peek])
+#
+# Read and return the specified number of bytes from handle. Return undef
+# if the number of bytes could not be read. If PEEK is non-zero, reset
+# file position after read.
+#
+
+sub graph_read(*$;$$)
+{
+	my ($handle, $length, $desc, $peek) = @_;
+	my $data;
+	my $result;
+	my $pos;
+
+	graph_expect($desc);
+	if ($peek) {
+		$pos = tell($handle);
+		if ($pos == -1) {
+			warn("Could not get current file position: $!\n");
+			return undef;
+		}
+	}
+	$result = read($handle, $data, $length);
+	if ($debug) {
+		my $op = $peek ? "peek" : "read";
+		my $ascii = "";
+		my $hex = "";
+		my $i;
+
+		print(STDERR "DEBUG: $op($length)=$result: ");
+		for ($i = 0; $i < length($data); $i++) {
+			my $c = substr($data, $i, 1);;
+			my $n = ord($c);
+
+			$hex .= sprintf("%02x ", $n);
+			if ($n >= 32 && $n <= 127) {
+				$ascii .= $c;
+			} else {
+				$ascii .= ".";
+			}
+		}
+		print(STDERR "$hex |$ascii|");
+		print(STDERR "\n");
+	}
+	if ($peek) {
+		if (!seek($handle, $pos, 0)) {
+			warn("Could not set file position: $!\n");
+			return undef;
+		}
+	}
+	if ($result != $length) {
+		return undef;
+	}
+	return $data;
+}
+
+#
+# graph_skip(handle, bytes[, description])
+#
+# Read and discard the specified number of bytes from handle. Return non-zero
+# if bytes could be read, zero otherwise.
+#
+
+sub graph_skip(*$;$)
+{
+	my ($handle, $length, $desc) = @_;
+
+	if (defined(graph_read($handle, $length, $desc))) {
+		return 1;
+	}
+	return 0;
+}
+
+#
+# uniq(list)
+#
+# Return list without duplicate entries.
+#
+
+sub uniq(@)
+{
+	my (@list) = @_;
+	my @new_list;
+	my %known;
+
+	foreach my $item (@list) {
+		next if ($known{$item});
+		$known{$item} = 1;
+		push(@new_list, $item);
+	}
+
+	return @new_list;
+}
+
+#
+# sort_uniq(list)
+#
+# Return list in numerically ascending order and without duplicate entries.
+#
+
+sub sort_uniq(@)
+{
+	my (@list) = @_;
+	my %hash;
+
+	foreach (@list) {
+		$hash{$_} = 1;
+	}
+	return sort { $a <=> $b } keys(%hash);
+}
+
+#
+# sort_uniq_lex(list)
+#
+# Return list in lexically ascending order and without duplicate entries.
+#
+
+sub sort_uniq_lex(@)
+{
+	my (@list) = @_;
+	my %hash;
+
+	foreach (@list) {
+		$hash{$_} = 1;
+	}
+	return sort keys(%hash);
+}
+
+#
+# parent_dir(dir)
+#
+# Return parent directory for DIR. DIR must not contain relative path
+# components.
+#
+
+sub parent_dir($)
+{
+	my ($dir) = @_;
+	my ($v, $d, $f) = splitpath($dir, 1);
+	my @dirs = splitdir($d);
+
+	pop(@dirs);
+
+	return catpath($v, catdir(@dirs), $f);
+}
+
+#
+# find_base_from_graph(base_dir, instr, graph)
+#
+# Try to determine the base directory of the graph file specified by INSTR
+# and GRAPH. The base directory is the base for all relative filenames in
+# the graph file. It is defined by the current working directory at time
+# of compiling the source file.
+#
+# This function implements a heuristic which relies on the following
+# assumptions:
+# - all files used for compilation are still present at their location
+# - the base directory is either BASE_DIR or one of its parent directories
+# - files by the same name are not present in multiple parent directories
+#
+
+sub find_base_from_graph($$$)
+{
+	my ($base_dir, $instr, $graph) = @_;
+	my $old_base;
+	my $best_miss;
+	my $best_base;
+	my %rel_files;
+
+	# Determine list of relative paths
+	foreach my $filename (keys(%{$instr}), keys(%{$graph})) {
+		next if (file_name_is_absolute($filename));
+
+		$rel_files{$filename} = 1;
+	}
+
+	# Early exit if there are no relative paths
+	return $base_dir if (!%rel_files);
+
+	do {
+		my $miss = 0;
+
+		foreach my $filename (keys(%rel_files)) {
+			if (!-e solve_relative_path($base_dir, $filename)) {
+				$miss++;
+			}
+		}
+
+		debug("base_dir=$base_dir miss=$miss\n");
+
+		# Exit if we find an exact match with no misses
+		return $base_dir if ($miss == 0);
+
+		# No exact match, aim for the one with the least source file
+		# misses
+		if (!defined($best_base) || $miss < $best_miss) {
+			$best_base = $base_dir;
+			$best_miss = $miss;
+		}
+
+		# Repeat until there's no more parent directory
+		$old_base = $base_dir;
+		$base_dir = parent_dir($base_dir);
+	} while ($old_base ne $base_dir);
+
+	return $best_base;
+}
+
+#
+# adjust_graph_filenames(base_dir, instr, graph)
+#
+# Make relative paths in INSTR and GRAPH absolute and apply
+# geninfo_adjust_src_path setting to graph file data.
+#
+
+sub adjust_graph_filenames($$$)
+{
+	my ($base_dir, $instr, $graph) = @_;
+
+	foreach my $filename (keys(%{$instr})) {
+		my $old_filename = $filename;
+
+		# Convert to absolute canonical form
+		$filename = solve_relative_path($base_dir, $filename);
+
+		# Apply adjustment
+		if (defined($adjust_src_pattern)) {
+			$filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+		}
+
+		if ($filename ne $old_filename) {
+			$instr->{$filename} = delete($instr->{$old_filename});
+		}
+	}
+
+	foreach my $filename (keys(%{$graph})) {
+		my $old_filename = $filename;
+
+		# Make absolute
+		# Convert to absolute canonical form
+		$filename = solve_relative_path($base_dir, $filename);
+
+		# Apply adjustment
+		if (defined($adjust_src_pattern)) {
+			$filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+		}
+
+		if ($filename ne $old_filename) {
+			$graph->{$filename} = delete($graph->{$old_filename});
+		}
+	}
+
+	return ($instr, $graph);
+}
+
+#
+# graph_cleanup(graph)
+#
+# Remove entries for functions with no lines. Remove duplicate line numbers.
+# Sort list of line numbers numerically ascending.
+#
+
+sub graph_cleanup($)
+{
+	my ($graph) = @_;
+	my $filename;
+
+	foreach $filename (keys(%{$graph})) {
+		my $per_file = $graph->{$filename};
+		my $function;
+
+		foreach $function (keys(%{$per_file})) {
+			my $lines = $per_file->{$function};
+
+			if (scalar(@$lines) == 0) {
+				# Remove empty function
+				delete($per_file->{$function});
+				next;
+			}
+			# Normalize list
+			$per_file->{$function} = [ uniq(@$lines) ];
+		}
+		if (scalar(keys(%{$per_file})) == 0) {
+			# Remove empty file
+			delete($graph->{$filename});
+		}
+	}
+}
+
+#
+# graph_find_base(bb)
+#
+# Try to identify the filename which is the base source file for the
+# specified bb data.
+#
+
+sub graph_find_base($)
+{
+	my ($bb) = @_;
+	my %file_count;
+	my $basefile;
+	my $file;
+	my $func;
+	my $filedata;
+	my $count;
+	my $num;
+
+	# Identify base name for this bb data.
+	foreach $func (keys(%{$bb})) {
+		$filedata = $bb->{$func};
+
+		foreach $file (keys(%{$filedata})) {
+			$count = $file_count{$file};
+
+			# Count file occurrence
+			$file_count{$file} = defined($count) ? $count + 1 : 1;
+		}
+	}
+	$count = 0;
+	$num = 0;
+	foreach $file (keys(%file_count)) {
+		if ($file_count{$file} > $count) {
+			# The file that contains code for the most functions
+			# is likely the base file
+			$count = $file_count{$file};
+			$num = 1;
+			$basefile = $file;
+		} elsif ($file_count{$file} == $count) {
+			# If more than one file could be the basefile, we
+			# don't have a basefile
+			$basefile = undef;
+		}
+	}
+
+	return $basefile;
+}
+
+#
+# graph_from_bb(bb, fileorder, bb_filename, fileorder_first)
+#
+# Convert data from bb to the graph format and list of instrumented lines.
+#
+# If FILEORDER_FIRST is set, use fileorder data to determine a functions
+# base source file.
+#
+# Returns (instr, graph).
+#
+# bb         : function name -> file data
+#            : undef -> file order
+# file data  : filename -> line data
+# line data  : [ line1, line2, ... ]
+#
+# file order : function name -> [ filename1, filename2, ... ]
+#
+# graph         : file name -> function data
+# function data : function name -> line data
+# line data     : [ line1, line2, ... ]
+#
+# instr     : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+
+sub graph_from_bb($$$$)
+{
+	my ($bb, $fileorder, $bb_filename, $fileorder_first) = @_;
+	my $graph = {};
+	my $instr = {};
+	my $basefile;
+	my $file;
+	my $func;
+	my $filedata;
+	my $linedata;
+	my $order;
+
+	$basefile = graph_find_base($bb);
+	# Create graph structure
+	foreach $func (keys(%{$bb})) {
+		$filedata = $bb->{$func};
+		$order = $fileorder->{$func};
+
+		# Account for lines in functions
+		if (defined($basefile) && defined($filedata->{$basefile}) &&
+		    !$fileorder_first) {
+			# If the basefile contributes to this function,
+			# account this function to the basefile.
+			$graph->{$basefile}->{$func} = $filedata->{$basefile};
+		} else {
+			# If the basefile does not contribute to this function,
+			# account this function to the first file contributing
+			# lines.
+			$graph->{$order->[0]}->{$func} =
+				$filedata->{$order->[0]};
+		}
+
+		foreach $file (keys(%{$filedata})) {
+			# Account for instrumented lines
+			$linedata = $filedata->{$file};
+			push(@{$instr->{$file}}, @$linedata);
+		}
+	}
+	# Clean up array of instrumented lines
+	foreach $file (keys(%{$instr})) {
+		$instr->{$file} = [ sort_uniq(@{$instr->{$file}}) ];
+	}
+
+	return ($instr, $graph);
+}
+
+#
+# graph_add_order(fileorder, function, filename)
+#
+# Add an entry for filename to the fileorder data set for function.
+#
+
+sub graph_add_order($$$)
+{
+	my ($fileorder, $function, $filename) = @_;
+	my $item;
+	my $list;
+
+	$list = $fileorder->{$function};
+	foreach $item (@$list) {
+		if ($item eq $filename) {
+			return;
+		}
+	}
+	push(@$list, $filename);
+	$fileorder->{$function} = $list;
+}
+
+#
+# read_bb_word(handle[, description])
+#
+# Read and return a word in .bb format from handle.
+#
+
+sub read_bb_word(*;$)
+{
+	my ($handle, $desc) = @_;
+
+	return graph_read($handle, 4, $desc);
+}
+
+#
+# read_bb_value(handle[, description])
+#
+# Read a word in .bb format from handle and return the word and its integer
+# value.
+#
+
+sub read_bb_value(*;$)
+{
+	my ($handle, $desc) = @_;
+	my $word;
+
+	$word = read_bb_word($handle, $desc);
+	return undef if (!defined($word));
+
+	return ($word, unpack("V", $word));
+}
+
+#
+# read_bb_string(handle, delimiter)
+#
+# Read and return a string in .bb format from handle up to the specified
+# delimiter value.
+#
+
+sub read_bb_string(*$)
+{
+	my ($handle, $delimiter) = @_;
+	my $word;
+	my $value;
+	my $string = "";
+
+	graph_expect("string");
+	do {
+		($word, $value) = read_bb_value($handle, "string or delimiter");
+		return undef if (!defined($value));
+		if ($value != $delimiter) {
+			$string .= $word;
+		}
+	} while ($value != $delimiter);
+	$string =~ s/\0//g;
+
+	return $string;
+}
+
+#
+# read_bb(filename)
+#
+# Read the contents of the specified .bb file and return (instr, graph), where:
+#
+#   instr     : filename -> line data
+#   line data : [ line1, line2, ... ]
+#
+#   graph     :     filename -> file_data
+#   file_data : function name -> line_data
+#   line_data : [ line1, line2, ... ]
+#
+# See the gcov info pages of gcc 2.95 for a description of the .bb file format.
+#
+
+sub read_bb($)
+{
+	my ($bb_filename) = @_;
+	my $minus_one = 0x80000001;
+	my $minus_two = 0x80000002;
+	my $value;
+	my $filename;
+	my $function;
+	my $bb = {};
+	my $fileorder = {};
+	my $instr;
+	my $graph;
+	local *HANDLE;
+
+	open(HANDLE, "<", $bb_filename) or goto open_error;
+	binmode(HANDLE);
+	while (!eof(HANDLE)) {
+		$value = read_bb_value(*HANDLE, "data word");
+		goto incomplete if (!defined($value));
+		if ($value == $minus_one) {
+			# Source file name
+			graph_expect("filename");
+			$filename = read_bb_string(*HANDLE, $minus_one);
+			goto incomplete if (!defined($filename));
+		} elsif ($value == $minus_two) {
+			# Function name
+			graph_expect("function name");
+			$function = read_bb_string(*HANDLE, $minus_two);
+			goto incomplete if (!defined($function));
+		} elsif ($value > 0) {
+			# Line number
+			if (!defined($filename) || !defined($function)) {
+				warn("WARNING: unassigned line number ".
+				     "$value\n");
+				next;
+			}
+			push(@{$bb->{$function}->{$filename}}, $value);
+			graph_add_order($fileorder, $function, $filename);
+		}
+	}
+	close(HANDLE);
+
+	($instr, $graph) = graph_from_bb($bb, $fileorder, $bb_filename, 0);
+	graph_cleanup($graph);
+
+	return ($instr, $graph);
+
+open_error:
+	graph_error($bb_filename, "could not open file");
+	return undef;
+incomplete:
+	graph_error($bb_filename, "reached unexpected end of file");
+	return undef;
+}
+
+#
+# read_bbg_word(handle[, description])
+#
+# Read and return a word in .bbg format.
+#
+
+sub read_bbg_word(*;$)
+{
+	my ($handle, $desc) = @_;
+
+	return graph_read($handle, 4, $desc);
+}
+
+#
+# read_bbg_value(handle[, description])
+#
+# Read a word in .bbg format from handle and return its integer value.
+#
+
+sub read_bbg_value(*;$)
+{
+	my ($handle, $desc) = @_;
+	my $word;
+
+	$word = read_bbg_word($handle, $desc);
+	return undef if (!defined($word));
+
+	return unpack("N", $word);
+}
+
+#
+# read_bbg_string(handle)
+#
+# Read and return a string in .bbg format.
+#
+
+sub read_bbg_string(*)
+{
+	my ($handle, $desc) = @_;
+	my $length;
+	my $string;
+
+	graph_expect("string");
+	# Read string length
+	$length = read_bbg_value($handle, "string length");
+	return undef if (!defined($length));
+	if ($length == 0) {
+		return "";
+	}
+	# Read string
+	$string = graph_read($handle, $length, "string");
+	return undef if (!defined($string));
+	# Skip padding
+	graph_skip($handle, 4 - $length % 4, "string padding") or return undef;
+
+	return $string;
+}
+
+#
+# read_bbg_lines_record(handle, bbg_filename, bb, fileorder, filename,
+#                       function)
+#
+# Read a bbg format lines record from handle and add the relevant data to
+# bb and fileorder. Return filename on success, undef on error.
+#
+
+sub read_bbg_lines_record(*$$$$$)
+{
+	my ($handle, $bbg_filename, $bb, $fileorder, $filename, $function) = @_;
+	my $string;
+	my $lineno;
+
+	graph_expect("lines record");
+	# Skip basic block index
+	graph_skip($handle, 4, "basic block index") or return undef;
+	while (1) {
+		# Read line number
+		$lineno = read_bbg_value($handle, "line number");
+		return undef if (!defined($lineno));
+		if ($lineno == 0) {
+			# Got a marker for a new filename
+			graph_expect("filename");
+			$string = read_bbg_string($handle);
+			return undef if (!defined($string));
+			# Check for end of record
+			if ($string eq "") {
+				return $filename;
+			}
+			$filename = $string;
+			if (!exists($bb->{$function}->{$filename})) {
+				$bb->{$function}->{$filename} = [];
+			}
+			next;
+		}
+		# Got an actual line number
+		if (!defined($filename)) {
+			warn("WARNING: unassigned line number in ".
+			     "$bbg_filename\n");
+			next;
+		}
+		push(@{$bb->{$function}->{$filename}}, $lineno);
+		graph_add_order($fileorder, $function, $filename);
+	}
+}
+
+#
+# read_bbg(filename)
+#
+# Read the contents of the specified .bbg file and return the following mapping:
+#   graph:     filename -> file_data
+#   file_data: function name -> line_data
+#   line_data: [ line1, line2, ... ]
+#
+# See the gcov-io.h file in the SLES 9 gcc 3.3.3 source code for a description
+# of the .bbg format.
+#
+
+sub read_bbg($)
+{
+	my ($bbg_filename) = @_;
+	my $file_magic = 0x67626267;
+	my $tag_function = 0x01000000;
+	my $tag_lines = 0x01450000;
+	my $word;
+	my $tag;
+	my $length;
+	my $function;
+	my $filename;
+	my $bb = {};
+	my $fileorder = {};
+	my $instr;
+	my $graph;
+	local *HANDLE;
+
+	open(HANDLE, "<", $bbg_filename) or goto open_error;
+	binmode(HANDLE);
+	# Read magic
+	$word = read_bbg_value(*HANDLE, "file magic");
+	goto incomplete if (!defined($word));
+	# Check magic
+	if ($word != $file_magic) {
+		goto magic_error;
+	}
+	# Skip version
+	graph_skip(*HANDLE, 4, "version") or goto incomplete;
+	while (!eof(HANDLE)) {
+		# Read record tag
+		$tag = read_bbg_value(*HANDLE, "record tag");
+		goto incomplete if (!defined($tag));
+		# Read record length
+		$length = read_bbg_value(*HANDLE, "record length");
+		goto incomplete if (!defined($tag));
+		if ($tag == $tag_function) {
+			graph_expect("function record");
+			# Read function name
+			graph_expect("function name");
+			$function = read_bbg_string(*HANDLE);
+			goto incomplete if (!defined($function));
+			$filename = undef;
+			# Skip function checksum
+			graph_skip(*HANDLE, 4, "function checksum")
+				or goto incomplete;
+		} elsif ($tag == $tag_lines) {
+			# Read lines record
+			$filename = read_bbg_lines_record(HANDLE, $bbg_filename,
+					  $bb, $fileorder, $filename,
+					  $function);
+			goto incomplete if (!defined($filename));
+		} else {
+			# Skip record contents
+			graph_skip(*HANDLE, $length, "unhandled record")
+				or goto incomplete;
+		}
+	}
+	close(HANDLE);
+	($instr, $graph) = graph_from_bb($bb, $fileorder, $bbg_filename, 0);
+
+	graph_cleanup($graph);
+
+	return ($instr, $graph);
+
+open_error:
+	graph_error($bbg_filename, "could not open file");
+	return undef;
+incomplete:
+	graph_error($bbg_filename, "reached unexpected end of file");
+	return undef;
+magic_error:
+	graph_error($bbg_filename, "found unrecognized bbg file magic");
+	return undef;
+}
+
+#
+# read_gcno_word(handle[, description, peek])
+#
+# Read and return a word in .gcno format.
+#
+
+sub read_gcno_word(*;$$)
+{
+	my ($handle, $desc, $peek) = @_;
+
+	return graph_read($handle, 4, $desc, $peek);
+}
+
+#
+# read_gcno_value(handle, big_endian[, description, peek])
+#
+# Read a word in .gcno format from handle and return its integer value
+# according to the specified endianness. If PEEK is non-zero, reset file
+# position after read.
+#
+
+sub read_gcno_value(*$;$$)
+{
+	my ($handle, $big_endian, $desc, $peek) = @_;
+	my $word;
+	my $pos;
+
+	$word = read_gcno_word($handle, $desc, $peek);
+	return undef if (!defined($word));
+	if ($big_endian) {
+		return unpack("N", $word);
+	} else {
+		return unpack("V", $word);
+	}
+}
+
+#
+# read_gcno_string(handle, big_endian)
+#
+# Read and return a string in .gcno format.
+#
+
+sub read_gcno_string(*$)
+{
+	my ($handle, $big_endian) = @_;
+	my $length;
+	my $string;
+
+	graph_expect("string");
+	# Read string length
+	$length = read_gcno_value($handle, $big_endian, "string length");
+	return undef if (!defined($length));
+	if ($length == 0) {
+		return "";
+	}
+	$length *= 4;
+	# Read string
+	$string = graph_read($handle, $length, "string and padding");
+	return undef if (!defined($string));
+	$string =~ s/\0//g;
+
+	return $string;
+}
+
+#
+# read_gcno_lines_record(handle, gcno_filename, bb, fileorder, filename,
+#                        function, big_endian)
+#
+# Read a gcno format lines record from handle and add the relevant data to
+# bb and fileorder. Return filename on success, undef on error.
+#
+
+sub read_gcno_lines_record(*$$$$$$)
+{
+	my ($handle, $gcno_filename, $bb, $fileorder, $filename, $function,
+	    $big_endian) = @_;
+	my $string;
+	my $lineno;
+
+	graph_expect("lines record");
+	# Skip basic block index
+	graph_skip($handle, 4, "basic block index") or return undef;
+	while (1) {
+		# Read line number
+		$lineno = read_gcno_value($handle, $big_endian, "line number");
+		return undef if (!defined($lineno));
+		if ($lineno == 0) {
+			# Got a marker for a new filename
+			graph_expect("filename");
+			$string = read_gcno_string($handle, $big_endian);
+			return undef if (!defined($string));
+			# Check for end of record
+			if ($string eq "") {
+				return $filename;
+			}
+			$filename = $string;
+			if (!exists($bb->{$function}->{$filename})) {
+				$bb->{$function}->{$filename} = [];
+			}
+			next;
+		}
+		# Got an actual line number
+		if (!defined($filename)) {
+			warn("WARNING: unassigned line number in ".
+			     "$gcno_filename\n");
+			next;
+		}
+		# Add to list
+		push(@{$bb->{$function}->{$filename}}, $lineno);
+		graph_add_order($fileorder, $function, $filename);
+	}
+}
+
+#
+# determine_gcno_split_crc(handle, big_endian, rec_length, version)
+#
+# Determine if HANDLE refers to a .gcno file with a split checksum function
+# record format. Return non-zero in case of split checksum format, zero
+# otherwise, undef in case of read error.
+#
+
+sub determine_gcno_split_crc($$$$)
+{
+	my ($handle, $big_endian, $rec_length, $version) = @_;
+	my $strlen;
+	my $overlong_string;
+
+	return 1 if ($version >= $GCOV_VERSION_4_7_0);
+	return 1 if (is_compat($COMPAT_MODE_SPLIT_CRC));
+
+	# Heuristic:
+	# Decide format based on contents of next word in record:
+	# - pre-gcc 4.7
+	#   This is the function name length / 4 which should be
+	#   less than the remaining record length
+	# - gcc 4.7
+	#   This is a checksum, likely with high-order bits set,
+	#   resulting in a large number
+	$strlen = read_gcno_value($handle, $big_endian, undef, 1);
+	return undef if (!defined($strlen));
+	$overlong_string = 1 if ($strlen * 4 >= $rec_length - 12);
+
+	if ($overlong_string) {
+		if (is_compat_auto($COMPAT_MODE_SPLIT_CRC)) {
+			info("Auto-detected compatibility mode for split ".
+			     "checksum .gcno file format\n");
+
+			return 1;
+		} else {
+			# Sanity check
+			warn("Found overlong string in function record: ".
+			     "try '--compat split_crc'\n");
+		}
+	}
+
+	return 0;
+}
+
+#
+# read_gcno_function_record(handle, graph, big_endian, rec_length, version)
+#
+# Read a gcno format function record from handle and add the relevant data
+# to graph. Return (filename, function, artificial) on success, undef on error.
+#
+
+sub read_gcno_function_record(*$$$$$)
+{
+	my ($handle, $bb, $fileorder, $big_endian, $rec_length, $version) = @_;
+	my $filename;
+	my $function;
+	my $lineno;
+	my $lines;
+	my $artificial;
+
+	graph_expect("function record");
+	# Skip ident and checksum
+	graph_skip($handle, 8, "function ident and checksum") or return undef;
+	# Determine if this is a function record with split checksums
+	if (!defined($gcno_split_crc)) {
+		$gcno_split_crc = determine_gcno_split_crc($handle, $big_endian,
+							   $rec_length,
+							   $version);
+		return undef if (!defined($gcno_split_crc));
+	}
+	# Skip cfg checksum word in case of split checksums
+	graph_skip($handle, 4, "function cfg checksum") if ($gcno_split_crc);
+	# Read function name
+	graph_expect("function name");
+	$function = read_gcno_string($handle, $big_endian);
+	return undef if (!defined($function));
+	if ($version >= $GCOV_VERSION_8_0_0) {
+		$artificial = read_gcno_value($handle, $big_endian,
+					      "compiler-generated entity flag");
+		return undef if (!defined($artificial));
+	}
+	# Read filename
+	graph_expect("filename");
+	$filename = read_gcno_string($handle, $big_endian);
+	return undef if (!defined($filename));
+	# Read first line number
+	$lineno = read_gcno_value($handle, $big_endian, "initial line number");
+	return undef if (!defined($lineno));
+	# Skip column and ending line number
+	if ($version >= $GCOV_VERSION_8_0_0) {
+		graph_skip($handle, 4, "column number") or return undef;
+		graph_skip($handle, 4, "ending line number") or return undef;
+	}
+	# Add to list
+	push(@{$bb->{$function}->{$filename}}, $lineno);
+	graph_add_order($fileorder, $function, $filename);
+
+	return ($filename, $function, $artificial);
+}
+
+#
+# map_gcno_version
+#
+# Map version number as found in .gcno files to the format used in geninfo.
+#
+
+sub map_gcno_version($)
+{
+	my ($version) = @_;
+	my ($a, $b, $c);
+	my ($major, $minor);
+
+	$a = $version >> 24;
+	$b = $version >> 16 & 0xff;
+	$c = $version >> 8 & 0xff;
+
+	if ($a < ord('A')) {
+		$major = $a - ord('0');
+		$minor = ($b - ord('0')) * 10 + $c - ord('0');
+	} else {
+		$major = ($a - ord('A')) * 10 + $b - ord('0');
+		$minor = $c - ord('0');
+	}
+
+	return $major << 16 | $minor << 8;
+}
+
+sub remove_fn_from_hash($$)
+{
+	my ($hash, $fns) = @_;
+
+	foreach my $fn (@$fns) {
+		delete($hash->{$fn});
+	}
+}
+
+#
+# read_gcno(filename)
+#
+# Read the contents of the specified .gcno file and return the following
+# mapping:
+#   graph:    filename -> file_data
+#   file_data: function name -> line_data
+#   line_data: [ line1, line2, ... ]
+#
+# See the gcov-io.h file in the gcc 3.3 source code for a description of
+# the .gcno format.
+#
+
+sub read_gcno($)
+{
+	my ($gcno_filename) = @_;
+	my $file_magic = 0x67636e6f;
+	my $tag_function = 0x01000000;
+	my $tag_lines = 0x01450000;
+	my $big_endian;
+	my $word;
+	my $tag;
+	my $length;
+	my $filename;
+	my $function;
+	my $bb = {};
+	my $fileorder = {};
+	my $instr;
+	my $graph;
+	my $filelength;
+	my $version;
+	my $artificial;
+	my @artificial_fns;
+	local *HANDLE;
+
+	open(HANDLE, "<", $gcno_filename) or goto open_error;
+	$filelength = (stat(HANDLE))[7];
+	binmode(HANDLE);
+	# Read magic
+	$word = read_gcno_word(*HANDLE, "file magic");
+	goto incomplete if (!defined($word));
+	# Determine file endianness
+	if (unpack("N", $word) == $file_magic) {
+		$big_endian = 1;
+	} elsif (unpack("V", $word) == $file_magic) {
+		$big_endian = 0;
+	} else {
+		goto magic_error;
+	}
+	# Read version
+	$version = read_gcno_value(*HANDLE, $big_endian, "compiler version");
+	$version = map_gcno_version($version);
+	debug(sprintf("found version 0x%08x\n", $version));
+	# Skip stamp
+	graph_skip(*HANDLE, 4, "file timestamp") or goto incomplete;
+	if ($version >= $GCOV_VERSION_8_0_0) {
+		graph_skip(*HANDLE, 4, "support unexecuted blocks flag")
+			or goto incomplete;
+	}
+	while (!eof(HANDLE)) {
+		my $next_pos;
+		my $curr_pos;
+
+		# Read record tag
+		$tag = read_gcno_value(*HANDLE, $big_endian, "record tag");
+		goto incomplete if (!defined($tag));
+		# Read record length
+		$length = read_gcno_value(*HANDLE, $big_endian,
+					  "record length");
+		goto incomplete if (!defined($length));
+		# Convert length to bytes
+		$length *= 4;
+		# Calculate start of next record
+		$next_pos = tell(HANDLE);
+		goto tell_error if ($next_pos == -1);
+		$next_pos += $length;
+		# Catch garbage at the end of a gcno file
+		if ($next_pos > $filelength) {
+			debug("Overlong record: file_length=$filelength ".
+			      "rec_length=$length\n");
+			warn("WARNING: $gcno_filename: Overlong record at end ".
+			     "of file!\n");
+			last;
+		}
+		# Process record
+		if ($tag == $tag_function) {
+			($filename, $function, $artificial) =
+				read_gcno_function_record(
+				*HANDLE, $bb, $fileorder, $big_endian,
+				$length, $version);
+			goto incomplete if (!defined($function));
+			push(@artificial_fns, $function) if ($artificial);
+		} elsif ($tag == $tag_lines) {
+			# Read lines record
+			$filename = read_gcno_lines_record(*HANDLE,
+					$gcno_filename, $bb, $fileorder,
+					$filename, $function, $big_endian);
+			goto incomplete if (!defined($filename));
+		} else {
+			# Skip record contents
+			graph_skip(*HANDLE, $length, "unhandled record")
+				or goto incomplete;
+		}
+		# Ensure that we are at the start of the next record
+		$curr_pos = tell(HANDLE);
+		goto tell_error if ($curr_pos == -1);
+		next if ($curr_pos == $next_pos);
+		goto record_error if ($curr_pos > $next_pos);
+		graph_skip(*HANDLE, $next_pos - $curr_pos,
+			   "unhandled record content")
+			or goto incomplete;
+	}
+	close(HANDLE);
+
+	# Remove artificial functions from result data
+	remove_fn_from_hash($bb, \@artificial_fns);
+	remove_fn_from_hash($fileorder, \@artificial_fns);
+
+	($instr, $graph) = graph_from_bb($bb, $fileorder, $gcno_filename, 1);
+	graph_cleanup($graph);
+
+	return ($instr, $graph);
+
+open_error:
+	graph_error($gcno_filename, "could not open file");
+	return undef;
+incomplete:
+	graph_error($gcno_filename, "reached unexpected end of file");
+	return undef;
+magic_error:
+	graph_error($gcno_filename, "found unrecognized gcno file magic");
+	return undef;
+tell_error:
+	graph_error($gcno_filename, "could not determine file position");
+	return undef;
+record_error:
+	graph_error($gcno_filename, "found unrecognized record format");
+	return undef;
+}
+
+sub debug($)
+{
+	my ($msg) = @_;
+
+	return if (!$debug);
+	print(STDERR "DEBUG: $msg");
+}
+
+#
+# get_gcov_capabilities
+#
+# Determine the list of available gcov options.
+#
+
+sub get_gcov_capabilities()
+{
+	my $help = `$gcov_tool --help`;
+	my %capabilities;
+	my %short_option_translations = (
+		'a' => 'all-blocks',
+		'b' => 'branch-probabilities',
+		'c' => 'branch-counts',
+		'f' => 'function-summaries',
+		'h' => 'help',
+		'l' => 'long-file-names',
+		'n' => 'no-output',
+		'o' => 'object-directory',
+		'p' => 'preserve-paths',
+		'u' => 'unconditional-branches',
+		'v' => 'version',
+		'x' => 'hash-filenames',
+	);
+
+	foreach (split(/\n/, $help)) {
+		my $capability;
+		if (/--(\S+)/) {
+			$capability = $1;
+		} else {
+			# If the line provides a short option, translate it.
+			next if (!/^\s*-(\S)\s/);
+			$capability = $short_option_translations{$1};
+			next if not defined($capability);
+		}
+		next if ($capability eq 'help');
+		next if ($capability eq 'version');
+		next if ($capability eq 'object-directory');
+
+		$capabilities{$capability} = 1;
+		debug("gcov has capability '$capability'\n");
+	}
+
+	return \%capabilities;
+}
+
+#
+# parse_ignore_errors(@ignore_errors)
+#
+# Parse user input about which errors to ignore.
+#
+
+sub parse_ignore_errors(@)
+{
+	my (@ignore_errors) = @_;
+	my @items;
+	my $item;
+
+	return if (!@ignore_errors);
+
+	foreach $item (@ignore_errors) {
+		$item =~ s/\s//g;
+		if ($item =~ /,/) {
+			# Split and add comma-separated parameters
+			push(@items, split(/,/, $item));
+		} else {
+			# Add single parameter
+			push(@items, $item);
+		}
+	}
+	foreach $item (@items) {
+		my $item_id = $ERROR_ID{lc($item)};
+
+		if (!defined($item_id)) {
+			die("ERROR: unknown argument for --ignore-errors: ".
+			    "$item\n");
+		}
+		$ignore[$item_id] = 1;
+	}
+}
+
+#
+# is_external(filename)
+#
+# Determine if a file is located outside of the specified data directories.
+#
+
+sub is_external($)
+{
+	my ($filename) = @_;
+	my $dir;
+
+	foreach $dir (@internal_dirs) {
+		return 0 if ($filename =~ /^\Q$dir\/\E/);
+	}
+	return 1;
+}
+
+#
+# compat_name(mode)
+#
+# Return the name of compatibility mode MODE.
+#
+
+sub compat_name($)
+{
+	my ($mode) = @_;
+	my $name = $COMPAT_MODE_TO_NAME{$mode};
+
+	return $name if (defined($name));
+
+	return "<unknown>";
+}
+
+#
+# parse_compat_modes(opt)
+#
+# Determine compatibility mode settings.
+#
+
+sub parse_compat_modes($)
+{
+	my ($opt) = @_;
+	my @opt_list;
+	my %specified;
+
+	# Initialize with defaults
+	%compat_value = %COMPAT_MODE_DEFAULTS;
+
+	# Add old style specifications
+	if (defined($opt_compat_libtool)) {
+		$compat_value{$COMPAT_MODE_LIBTOOL} =
+			$opt_compat_libtool ? $COMPAT_VALUE_ON
+					    : $COMPAT_VALUE_OFF;
+	}
+
+	# Parse settings
+	if (defined($opt)) {
+		@opt_list = split(/\s*,\s*/, $opt);
+	}
+	foreach my $directive (@opt_list) {
+		my ($mode, $value);
+
+		# Either
+		#   mode=off|on|auto or
+		#   mode (implies on)
+		if ($directive !~ /^(\w+)=(\w+)$/ &&
+		    $directive !~ /^(\w+)$/) {
+			die("ERROR: Unknown compatibility mode specification: ".
+			    "$directive!\n");
+		}
+		# Determine mode
+		$mode = $COMPAT_NAME_TO_MODE{lc($1)};
+		if (!defined($mode)) {
+			die("ERROR: Unknown compatibility mode '$1'!\n");
+		}
+		$specified{$mode} = 1;
+		# Determine value
+		if (defined($2)) {
+			$value = $COMPAT_NAME_TO_VALUE{lc($2)};
+			if (!defined($value)) {
+				die("ERROR: Unknown compatibility mode ".
+				    "value '$2'!\n");
+			}
+		} else {
+			$value = $COMPAT_VALUE_ON;
+		}
+		$compat_value{$mode} = $value;
+	}
+	# Perform auto-detection
+	foreach my $mode (sort(keys(%compat_value))) {
+		my $value = $compat_value{$mode};
+		my $is_autodetect = "";
+		my $name = compat_name($mode);
+
+		if ($value == $COMPAT_VALUE_AUTO) {
+			my $autodetect = $COMPAT_MODE_AUTO{$mode};
+
+			if (!defined($autodetect)) {
+				die("ERROR: No auto-detection for ".
+				    "mode '$name' available!\n");
+			}
+
+			if (ref($autodetect) eq "CODE") {
+				$value = &$autodetect();
+				$compat_value{$mode} = $value;
+				$is_autodetect = " (auto-detected)";
+			}
+		}
+
+		if ($specified{$mode}) {
+			if ($value == $COMPAT_VALUE_ON) {
+				info("Enabling compatibility mode ".
+				     "'$name'$is_autodetect\n");
+			} elsif ($value == $COMPAT_VALUE_OFF) {
+				info("Disabling compatibility mode ".
+				     "'$name'$is_autodetect\n");
+			} else {
+				info("Using delayed auto-detection for ".
+				     "compatibility mode ".
+				     "'$name'\n");
+			}
+		}
+	}
+}
+
+sub compat_hammer_autodetect()
+{
+        if ($gcov_version_string =~ /suse/i && $gcov_version == 0x30303 ||
+            $gcov_version_string =~ /mandrake/i && $gcov_version == 0x30302)
+	{
+		info("Auto-detected compatibility mode for GCC 3.3 (hammer)\n");
+		return $COMPAT_VALUE_ON;
+	}
+	return $COMPAT_VALUE_OFF;
+}
+
+#
+# is_compat(mode)
+#
+# Return non-zero if compatibility mode MODE is enabled.
+#
+
+sub is_compat($)
+{
+	my ($mode) = @_;
+
+	return 1 if ($compat_value{$mode} == $COMPAT_VALUE_ON);
+	return 0;
+}
+
+#
+# is_compat_auto(mode)
+#
+# Return non-zero if compatibility mode MODE is set to auto-detect.
+#
+
+sub is_compat_auto($)
+{
+	my ($mode) = @_;
+
+	return 1 if ($compat_value{$mode} == $COMPAT_VALUE_AUTO);
+	return 0;
+}
diff --git a/externals/lcov/bin/genpng b/externals/lcov/bin/genpng
new file mode 100755
index 0000000000000000000000000000000000000000..943a49d5f0454e01aa12430fbc97a44805ac404e
--- /dev/null
+++ b/externals/lcov/bin/genpng
@@ -0,0 +1,389 @@
+#!/usr/bin/env perl
+#
+#   Copyright (c) International Business Machines  Corp., 2002
+#
+#   This program is free software;  you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY;  without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.                 
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program;  if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# genpng
+#
+#   This script creates an overview PNG image of a source code file by
+#   representing each source code character by a single pixel.
+#
+#   Note that the Perl module GD.pm is required for this script to work.
+#   It may be obtained from http://www.cpan.org
+#
+# History:
+#   2002-08-26: created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+#
+
+use strict;
+use warnings;
+use File::Basename; 
+use Getopt::Long;
+use Cwd qw/abs_path/;
+
+
+# Constants
+our $tool_dir		= abs_path(dirname($0));
+our $lcov_version	= "LCOV version 1.14";
+our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $tool_name		= basename($0);
+
+
+# Prototypes
+sub gen_png($$$@);
+sub check_and_load_module($);
+sub genpng_print_usage(*);
+sub genpng_process_file($$$$);
+sub genpng_warn_handler($);
+sub genpng_die_handler($);
+
+
+#
+# Code entry point
+#
+
+# Check whether required module GD.pm is installed
+if (check_and_load_module("GD"))
+{
+	# Note: cannot use die() to print this message because inserting this
+	# code into another script via do() would not fail as required!
+	print(STDERR <<END_OF_TEXT)
+ERROR: required module GD.pm not found on this system (see www.cpan.org).
+END_OF_TEXT
+	;
+	exit(2);
+}
+
+# Check whether we're called from the command line or from another script
+if (!caller)
+{
+	my $filename;
+	my $tab_size = 4;
+	my $width = 80;
+	my $out_filename;
+	my $help;
+	my $version;
+
+	$SIG{__WARN__} = \&genpng_warn_handler;
+	$SIG{__DIE__} = \&genpng_die_handler;
+
+	# Parse command line options
+	if (!GetOptions("tab-size=i" => \$tab_size,
+			"width=i" => \$width,
+			"output-filename=s" => \$out_filename,
+			"help" => \$help,
+			"version" => \$version))
+	{
+		print(STDERR "Use $tool_name --help to get usage ".
+		      "information\n");
+		exit(1);
+	}
+
+	$filename = $ARGV[0];
+
+	# Check for help flag
+	if ($help)
+	{
+		genpng_print_usage(*STDOUT);
+		exit(0);
+	}
+
+	# Check for version flag
+	if ($version)
+	{
+		print("$tool_name: $lcov_version\n");
+		exit(0);
+	}
+
+	# Check options
+	if (!$filename)
+	{
+		die("No filename specified\n");
+	}
+
+	# Check for output filename
+	if (!$out_filename)
+	{
+		$out_filename = "$filename.png";
+	}
+
+	genpng_process_file($filename, $out_filename, $width, $tab_size);
+	exit(0);
+}
+
+
+#
+# genpng_print_usage(handle)
+#
+# Write out command line usage information to given filehandle.
+#
+
+sub genpng_print_usage(*)
+{
+	local *HANDLE = $_[0];
+
+	print(HANDLE <<END_OF_USAGE)
+Usage: $tool_name [OPTIONS] SOURCEFILE
+
+Create an overview image for a given source code file of either plain text
+or .gcov file format.
+
+  -h, --help                        Print this help, then exit
+  -v, --version                     Print version number, then exit
+  -t, --tab-size TABSIZE            Use TABSIZE spaces in place of tab
+  -w, --width WIDTH                 Set width of output image to WIDTH pixel
+  -o, --output-filename FILENAME    Write image to FILENAME
+
+For more information see: $lcov_url
+END_OF_USAGE
+	;
+}
+
+
+#
+# check_and_load_module(module_name)
+#
+# Check whether a module by the given name is installed on this system
+# and make it known to the interpreter if available. Return undefined if it
+# is installed, an error message otherwise.
+#
+
+sub check_and_load_module($)
+{
+	eval("use $_[0];");
+	return $@;
+}
+
+
+#
+# genpng_process_file(filename, out_filename, width, tab_size)
+#
+
+sub genpng_process_file($$$$)
+{
+	my $filename		= $_[0];
+	my $out_filename	= $_[1];
+	my $width		= $_[2];
+	my $tab_size		= $_[3];
+	local *HANDLE;
+	my @source;
+
+	open(HANDLE, "<", $filename)
+		or die("ERROR: cannot open $filename!\n");
+
+	# Check for .gcov filename extension
+	if ($filename =~ /^(.*).gcov$/)
+	{
+		# Assume gcov text format
+		while (<HANDLE>)
+		{
+			if (/^\t\t(.*)$/)
+			{
+				# Uninstrumented line
+				push(@source, ":$1");
+			}
+			elsif (/^      ######    (.*)$/)
+			{
+				# Line with zero execution count
+				push(@source, "0:$1");
+			}
+			elsif (/^( *)(\d*)    (.*)$/)
+			{
+				# Line with positive execution count
+				push(@source, "$2:$3");
+			}
+		}
+	}
+	else
+	{
+		# Plain text file
+		while (<HANDLE>) { push(@source, ":$_"); }
+	}
+	close(HANDLE);
+
+	gen_png($out_filename, $width, $tab_size, @source);
+}
+
+
+#
+# gen_png(filename, width, tab_size, source)
+#
+# Write an overview PNG file to FILENAME. Source code is defined by SOURCE
+# which is a list of lines <count>:<source code> per source code line.
+# The output image will be made up of one pixel per character of source,
+# coloring will be done according to execution counts. WIDTH defines the
+# image width. TAB_SIZE specifies the number of spaces to use as replacement
+# string for tabulator signs in source code text.
+#
+# Die on error.
+#
+
+sub gen_png($$$@)
+{
+	my $filename = shift(@_);	# Filename for PNG file
+	my $overview_width = shift(@_);	# Imagewidth for image
+	my $tab_size = shift(@_);	# Replacement string for tab signs
+	my @source = @_;	# Source code as passed via argument 2
+	my $height;		# Height as define by source size
+	my $overview;		# Source code overview image data
+	my $col_plain_back;	# Color for overview background
+	my $col_plain_text;	# Color for uninstrumented text
+	my $col_cov_back;	# Color for background of covered lines
+	my $col_cov_text;	# Color for text of covered lines
+	my $col_nocov_back;	# Color for background of lines which
+				# were not covered (count == 0)
+	my $col_nocov_text;	# Color for test of lines which were not
+				# covered (count == 0)
+	my $col_hi_back;	# Color for background of highlighted lines
+	my $col_hi_text;	# Color for text of highlighted lines
+	my $line;		# Current line during iteration
+	my $row = 0;		# Current row number during iteration
+	my $column;		# Current column number during iteration
+	my $color_text;		# Current text color during iteration
+	my $color_back;		# Current background color during iteration
+	my $last_count;		# Count of last processed line
+	my $count;		# Count of current line
+	my $source;		# Source code of current line
+	my $replacement;	# Replacement string for tabulator chars
+	local *PNG_HANDLE;	# Handle for output PNG file
+
+	# Handle empty source files
+	if (!@source) {
+		@source = ( "" );
+	}
+	$height = scalar(@source);
+	# Create image
+	$overview = new GD::Image($overview_width, $height)
+		or die("ERROR: cannot allocate overview image!\n");
+
+	# Define colors
+	$col_plain_back	= $overview->colorAllocate(0xff, 0xff, 0xff);
+	$col_plain_text	= $overview->colorAllocate(0xaa, 0xaa, 0xaa);
+	$col_cov_back	= $overview->colorAllocate(0xaa, 0xa7, 0xef);
+	$col_cov_text	= $overview->colorAllocate(0x5d, 0x5d, 0xea);
+	$col_nocov_back = $overview->colorAllocate(0xff, 0x00, 0x00);
+	$col_nocov_text = $overview->colorAllocate(0xaa, 0x00, 0x00);
+	$col_hi_back = $overview->colorAllocate(0x00, 0xff, 0x00);
+	$col_hi_text = $overview->colorAllocate(0x00, 0xaa, 0x00);
+
+	# Visualize each line
+	foreach $line (@source)
+	{
+		# Replace tabs with spaces to keep consistent with source
+		# code view
+		while ($line =~ /^([^\t]*)(\t)/)
+		{
+			$replacement = " "x($tab_size - ((length($1) - 1) %
+				       $tab_size));
+			$line =~ s/^([^\t]*)(\t)/$1$replacement/;
+		}
+
+		# Skip lines which do not follow the <count>:<line>
+		# specification, otherwise $1 = count, $2 = source code
+		if (!($line =~ /(\*?)(\d*):(.*)$/)) { next; }
+		$count = $2;
+		$source = $3;
+
+		# Decide which color pair to use
+
+		# If this line was not instrumented but the one before was,
+		# take the color of that line to widen color areas in
+		# resulting image
+		if (($count eq "") && defined($last_count) &&
+		    ($last_count ne ""))
+		{
+			$count = $last_count;
+		}
+
+		if ($count eq "")
+		{
+			# Line was not instrumented
+			$color_text = $col_plain_text;
+			$color_back = $col_plain_back;
+		}
+		elsif ($count == 0)
+		{
+			# Line was instrumented but not executed
+			$color_text = $col_nocov_text;
+			$color_back = $col_nocov_back;
+		}
+		elsif ($1 eq "*")
+		{
+			# Line was highlighted
+			$color_text = $col_hi_text;
+			$color_back = $col_hi_back;
+		}
+		else
+		{
+			# Line was instrumented and executed
+			$color_text = $col_cov_text;
+			$color_back = $col_cov_back;
+		}
+
+		# Write one pixel for each source character
+		$column = 0;
+		foreach (split("", $source))
+		{
+			# Check for width
+			if ($column >= $overview_width) { last; }
+
+			if ($_ eq " ")
+			{
+				# Space
+				$overview->setPixel($column++, $row,
+						    $color_back);
+			}
+			else
+			{
+				# Text
+				$overview->setPixel($column++, $row,
+						    $color_text);
+			}
+		}
+
+		# Fill rest of line		
+		while ($column < $overview_width)
+		{
+			$overview->setPixel($column++, $row, $color_back);
+		}
+
+		$last_count = $2;
+
+		$row++;
+	}
+
+	# Write PNG file
+	open (PNG_HANDLE, ">", $filename)
+		or die("ERROR: cannot write png file $filename!\n");
+	binmode(*PNG_HANDLE);
+	print(PNG_HANDLE $overview->png());
+	close(PNG_HANDLE);
+}
+
+sub genpng_warn_handler($)
+{
+	my ($msg) = @_;
+
+	warn("$tool_name: $msg");
+}
+
+sub genpng_die_handler($)
+{
+	my ($msg) = @_;
+
+	die("$tool_name: $msg");
+}
diff --git a/externals/lcov/bin/get_changes.sh b/externals/lcov/bin/get_changes.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ec373b4f4f023207c5aed6383f293a5c8a4ab4e0
--- /dev/null
+++ b/externals/lcov/bin/get_changes.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+#
+# Usage: get_changes.sh
+#
+# Print lcov change log information as provided by Git
+
+TOOLDIR=$(cd $(dirname $0) >/dev/null ; pwd)
+
+cd $TOOLDIR
+
+if ! git --no-pager log --no-merges --decorate=short --color=never 2>/dev/null ; then
+	cat "$TOOLDIR/../CHANGES" 2>/dev/null
+fi 
diff --git a/externals/lcov/bin/get_version.sh b/externals/lcov/bin/get_version.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ac5a36314699c7ccfa374d14a1c6e5ab68a62270
--- /dev/null
+++ b/externals/lcov/bin/get_version.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+#
+# Usage: get_version.sh --version|--release|--full
+#
+# Print lcov version or release information as provided by Git, .version
+# or a fallback.
+
+TOOLDIR=$(cd $(dirname $0) >/dev/null ; pwd)
+GITVER=$(cd $TOOLDIR ; git describe --tags 2>/dev/null)
+
+if [ -z "$GITVER" ] ; then
+	# Get version information from file
+	if [ -e "$TOOLDIR/../.version" ] ; then
+		source "$TOOLDIR/../.version"
+	fi
+else
+	# Get version information from git
+	FULL=${GITVER:1}
+	VERSION=${GITVER%%-*}
+	VERSION=${VERSION:1}
+	if [ "${GITVER#*-}" != "$GITVER" ] ; then
+		RELEASE=${GITVER#*-}
+		RELEASE=${RELEASE/-/.}
+	fi
+fi
+
+# Fallback
+[ -z "$VERSION" ] && VERSION="1.0"
+[ -z "$RELEASE" ] && RELEASE="1"
+[ -z "$FULL" ]    && FULL="$VERSION"
+
+[ "$1" == "--version" ] && echo -n "$VERSION"
+[ "$1" == "--release" ] && echo -n "$RELEASE"
+[ "$1" == "--full"    ] && echo -n "$FULL"
diff --git a/externals/lcov/bin/install.sh b/externals/lcov/bin/install.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2cdef45b6ca50fe0f745140c860f15b06e883ede
--- /dev/null
+++ b/externals/lcov/bin/install.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+#
+# install.sh [--uninstall] sourcefile targetfile [install options]
+#
+
+
+# Check for uninstall option
+if test "x$1" == "x--uninstall" ; then
+  UNINSTALL=true
+  SOURCE=$2
+  TARGET=$3
+  shift 3
+else
+  UNINSTALL=false
+  SOURCE=$1
+  TARGET=$2
+  shift 2
+fi
+
+# Check usage
+if test -z "$SOURCE" || test -z "$TARGET" ; then
+  echo Usage: install.sh [--uninstall] source target [install options] >&2
+  exit 1
+fi
+
+
+#
+# do_install(SOURCE_FILE, TARGET_FILE)
+#
+
+do_install()
+{
+  local SOURCE=$1
+  local TARGET=$2
+  local PARAMS=$3
+
+  install -d $(dirname $TARGET)
+  install -p $PARAMS $SOURCE $TARGET
+  if [ -n "$LCOV_PERL_PATH" ] ; then
+    # Replace Perl interpreter specification
+    sed -e "1 s%^#\!.*perl.*$%#\!$LCOV_PERL_PATH%" -i $TARGET
+  fi
+}
+
+
+#
+# do_uninstall(SOURCE_FILE, TARGET_FILE)
+#
+
+do_uninstall()
+{
+  local SOURCE=$1
+  local TARGET=$2
+
+  # Does target exist?
+  if test -r $TARGET ; then
+    # Is target of the same version as this package?
+    if diff -I '^our \$lcov_version' -I '^\.TH ' -I '^#!' $SOURCE $TARGET >/dev/null; then
+      rm -f $TARGET
+    else
+      echo WARNING: Skipping uninstall for $TARGET - versions differ! >&2
+    fi
+  else
+    echo WARNING: Skipping uninstall for $TARGET - not installed! >&2
+  fi
+}
+
+
+# Call sub routine
+if $UNINSTALL ; then
+  do_uninstall $SOURCE $TARGET
+else
+  do_install $SOURCE $TARGET "$*"
+fi
+
+exit 0
diff --git a/externals/lcov/bin/lcov b/externals/lcov/bin/lcov
new file mode 100755
index 0000000000000000000000000000000000000000..33c9f4d16e718f2f76e83d090b2ed2beeec4435f
--- /dev/null
+++ b/externals/lcov/bin/lcov
@@ -0,0 +1,4329 @@
+#!/usr/bin/env perl
+#
+#   Copyright (c) International Business Machines  Corp., 2002,2012
+#
+#   This program is free software;  you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY;  without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.                 
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program;  if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# lcov
+#
+#   This is a wrapper script which provides a single interface for accessing
+#   LCOV coverage data.
+#
+#
+# History:
+#   2002-08-29 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+#                         IBM Lab Boeblingen
+#   2002-09-05 / Peter Oberparleiter: implemented --kernel-directory +
+#                multiple directories
+#   2002-10-16 / Peter Oberparleiter: implemented --add-tracefile option
+#   2002-10-17 / Peter Oberparleiter: implemented --extract option
+#   2002-11-04 / Peter Oberparleiter: implemented --list option
+#   2003-03-07 / Paul Larson: Changed to make it work with the latest gcov 
+#                kernel patch.  This will break it with older gcov-kernel
+#                patches unless you change the value of $gcovmod in this script
+#   2003-04-07 / Peter Oberparleiter: fixed bug which resulted in an error
+#                when trying to combine .info files containing data without
+#                a test name
+#   2003-04-10 / Peter Oberparleiter: extended Paul's change so that LCOV
+#                works both with the new and the old gcov-kernel patch
+#   2003-04-10 / Peter Oberparleiter: added $gcov_dir constant in anticipation
+#                of a possible move of the gcov kernel directory to another
+#                file system in a future version of the gcov-kernel patch
+#   2003-04-15 / Paul Larson: make info write to STDERR, not STDOUT
+#   2003-04-15 / Paul Larson: added --remove option
+#   2003-04-30 / Peter Oberparleiter: renamed --reset to --zerocounters
+#                to remove naming ambiguity with --remove
+#   2003-04-30 / Peter Oberparleiter: adjusted help text to include --remove
+#   2003-06-27 / Peter Oberparleiter: implemented --diff
+#   2003-07-03 / Peter Oberparleiter: added line checksum support, added
+#                --no-checksum
+#   2003-12-11 / Laurent Deniel: added --follow option
+#   2004-03-29 / Peter Oberparleiter: modified --diff option to better cope with
+#                ambiguous patch file entries, modified --capture option to use
+#                modprobe before insmod (needed for 2.6)
+#   2004-03-30 / Peter Oberparleiter: added --path option
+#   2004-08-09 / Peter Oberparleiter: added configuration file support
+#   2008-08-13 / Peter Oberparleiter: added function coverage support
+#
+
+use strict;
+use warnings;
+use File::Basename;
+use File::Path;
+use File::Find;
+use File::Temp qw /tempdir/;
+use File::Spec::Functions qw /abs2rel canonpath catdir catfile catpath
+			      file_name_is_absolute rootdir splitdir splitpath/;
+use Getopt::Long;
+use Cwd qw /abs_path getcwd/;
+
+
+# Global constants
+our $tool_dir		= abs_path(dirname($0));
+our $lcov_version	= "LCOV version 1.14";
+our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $tool_name		= basename($0);
+
+# Directory containing gcov kernel files
+our $gcov_dir;
+
+# Where to create temporary directories
+our $tmp_dir;
+
+# Internal constants
+our $GKV_PROC = 0;	# gcov-kernel data in /proc via external patch
+our $GKV_SYS = 1;	# gcov-kernel data in /sys via vanilla 2.6.31+
+our @GKV_NAME = ( "external", "upstream" );
+our $pkg_gkv_file = ".gcov_kernel_version";
+our $pkg_build_file = ".build_directory";
+
+# Branch data combination types
+our $BR_SUB = 0;
+our $BR_ADD = 1;
+
+# Prototypes
+sub print_usage(*);
+sub check_options();
+sub userspace_reset();
+sub userspace_capture();
+sub kernel_reset();
+sub kernel_capture();
+sub kernel_capture_initial();
+sub package_capture();
+sub add_traces();
+sub read_info_file($);
+sub get_info_entry($);
+sub set_info_entry($$$$$$$$$;$$$$$$);
+sub add_counts($$);
+sub merge_checksums($$$);
+sub combine_info_entries($$$);
+sub combine_info_files($$);
+sub write_info_file(*$);
+sub extract();
+sub remove();
+sub list();
+sub get_common_filename($$);
+sub read_diff($);
+sub diff();
+sub system_no_output($@);
+sub read_config($);
+sub apply_config($);
+sub info(@);
+sub create_temp_dir();
+sub transform_pattern($);
+sub warn_handler($);
+sub die_handler($);
+sub abort_handler($);
+sub temp_cleanup();
+sub setup_gkv();
+sub get_overall_line($$$$);
+sub print_overall_rate($$$$$$$$$);
+sub lcov_geninfo(@);
+sub create_package($$$;$);
+sub get_func_found_and_hit($);
+sub summary();
+sub rate($$;$$$);
+
+# Global variables & initialization
+our @directory;		# Specifies where to get coverage data from
+our @kernel_directory;	# If set, captures only from specified kernel subdirs
+our @add_tracefile;	# If set, reads in and combines all files in list
+our $list;		# If set, list contents of tracefile
+our $extract;		# If set, extracts parts of tracefile
+our $remove;		# If set, removes parts of tracefile
+our $diff;		# If set, modifies tracefile according to diff
+our $reset;		# If set, reset all coverage data to zero
+our $capture;		# If set, capture data
+our $output_filename;	# Name for file to write coverage data to
+our $test_name = "";	# Test case name
+our $quiet = "";	# If set, suppress information messages
+our $help;		# Help option flag
+our $version;		# Version option flag
+our $convert_filenames;	# If set, convert filenames when applying diff
+our $strip;		# If set, strip leading directories when applying diff
+our $temp_dir_name;	# Name of temporary directory
+our $cwd = `pwd`;	# Current working directory
+our $data_stdout;	# If set, indicates that data is written to stdout
+our $follow;		# If set, indicates that find shall follow links
+our $diff_path = "";	# Path removed from tracefile when applying diff
+our $base_directory;	# Base directory (cwd of gcc during compilation)
+our $checksum;		# If set, calculate a checksum for each line
+our $no_checksum;	# If set, don't calculate a checksum for each line
+our $compat_libtool;	# If set, indicates that libtool mode is to be enabled
+our $no_compat_libtool;	# If set, indicates that libtool mode is to be disabled
+our $gcov_tool;
+our @opt_ignore_errors;
+our $initial;
+our @include_patterns; # List of source file patterns to include
+our @exclude_patterns; # List of source file patterns to exclude
+our $no_recursion = 0;
+our $to_package;
+our $from_package;
+our $maxdepth;
+our $no_markers;
+our $config;		# Configuration file contents
+chomp($cwd);
+our @temp_dirs;
+our $gcov_gkv;		# gcov kernel support version found on machine
+our $opt_derive_func_data;
+our $opt_debug;
+our $opt_list_full_path;
+our $opt_no_list_full_path;
+our $opt_list_width = 80;
+our $opt_list_truncate_max = 20;
+our $opt_external;
+our $opt_no_external;
+our $opt_config_file;
+our %opt_rc;
+our @opt_summary;
+our $opt_compat;
+our $ln_overall_found;
+our $ln_overall_hit;
+our $fn_overall_found;
+our $fn_overall_hit;
+our $br_overall_found;
+our $br_overall_hit;
+our $func_coverage = 1;
+our $br_coverage = 0;
+
+
+#
+# Code entry point
+#
+
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+$SIG{'INT'} = \&abort_handler;
+$SIG{'QUIT'} = \&abort_handler;
+
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+	   "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
+
+{
+	# Remove spaces around rc options
+	my %new_opt_rc;
+
+	while (my ($key, $value) = each(%opt_rc)) {
+		$key =~ s/^\s+|\s+$//g;
+		$value =~ s/^\s+|\s+$//g;
+
+		$new_opt_rc{$key} = $value;
+	}
+	%opt_rc = %new_opt_rc;
+}
+
+# Read configuration file if available
+if (defined($opt_config_file)) {
+	$config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
+{
+	$config = read_config($ENV{"HOME"}."/.lcovrc");
+}
+elsif (-r "/etc/lcovrc")
+{
+	$config = read_config("/etc/lcovrc");
+} elsif (-r "/usr/local/etc/lcovrc")
+{
+	$config = read_config("/usr/local/etc/lcovrc");
+}
+
+if ($config || %opt_rc)
+{
+	# Copy configuration file and --rc values to variables
+	apply_config({
+		"lcov_gcov_dir"		=> \$gcov_dir,
+		"lcov_tmp_dir"		=> \$tmp_dir,
+		"lcov_list_full_path"	=> \$opt_list_full_path,
+		"lcov_list_width"	=> \$opt_list_width,
+		"lcov_list_truncate_max"=> \$opt_list_truncate_max,
+		"lcov_branch_coverage"	=> \$br_coverage,
+		"lcov_function_coverage"=> \$func_coverage,
+	});
+}
+
+# Parse command line options
+if (!GetOptions("directory|d|di=s" => \@directory,
+		"add-tracefile|a=s" => \@add_tracefile,
+		"list|l=s" => \$list,
+		"kernel-directory|k=s" => \@kernel_directory,
+		"extract|e=s" => \$extract,
+		"remove|r=s" => \$remove,
+		"diff=s" => \$diff,
+		"convert-filenames" => \$convert_filenames,
+		"strip=i" => \$strip,
+		"capture|c" => \$capture,
+		"output-file|o=s" => \$output_filename,
+		"test-name|t=s" => \$test_name,
+		"zerocounters|z" => \$reset,
+		"quiet|q" => \$quiet,
+		"help|h|?" => \$help,
+		"version|v" => \$version,
+		"follow|f" => \$follow,
+		"path=s" => \$diff_path,
+		"base-directory|b=s" => \$base_directory,
+		"checksum" => \$checksum,
+		"no-checksum" => \$no_checksum,
+		"compat-libtool" => \$compat_libtool,
+		"no-compat-libtool" => \$no_compat_libtool,
+		"gcov-tool=s" => \$gcov_tool,
+		"ignore-errors=s" => \@opt_ignore_errors,
+		"initial|i" => \$initial,
+		"include=s" => \@include_patterns,
+		"exclude=s" => \@exclude_patterns,
+		"no-recursion" => \$no_recursion,
+		"to-package=s" => \$to_package,
+		"from-package=s" => \$from_package,
+		"no-markers" => \$no_markers,
+		"derive-func-data" => \$opt_derive_func_data,
+		"debug" => \$opt_debug,
+		"list-full-path" => \$opt_list_full_path,
+		"no-list-full-path" => \$opt_no_list_full_path,
+		"external" => \$opt_external,
+		"no-external" => \$opt_no_external,
+		"summary=s" => \@opt_summary,
+		"compat=s" => \$opt_compat,
+		"config-file=s" => \$opt_config_file,
+		"rc=s%" => \%opt_rc,
+		))
+{
+	print(STDERR "Use $tool_name --help to get usage information\n");
+	exit(1);
+}
+else
+{
+	# Merge options
+	if (defined($no_checksum))
+	{
+		$checksum = ($no_checksum ? 0 : 1);
+		$no_checksum = undef;
+	}
+
+	if (defined($no_compat_libtool))
+	{
+		$compat_libtool = ($no_compat_libtool ? 0 : 1);
+		$no_compat_libtool = undef;
+	}
+
+	if (defined($opt_no_list_full_path))
+	{
+		$opt_list_full_path = ($opt_no_list_full_path ? 0 : 1);
+		$opt_no_list_full_path = undef;
+	}
+
+	if (defined($opt_no_external)) {
+		$opt_external = 0;
+		$opt_no_external = undef;
+	}
+}
+
+# Check for help option
+if ($help)
+{
+	print_usage(*STDOUT);
+	exit(0);
+}
+
+# Check for version option
+if ($version)
+{
+	print("$tool_name: $lcov_version\n");
+	exit(0);
+}
+
+# Check list width option
+if ($opt_list_width <= 40) {
+	die("ERROR: lcov_list_width parameter out of range (needs to be ".
+	    "larger than 40)\n");
+}
+
+# Normalize --path text
+$diff_path =~ s/\/$//;
+
+if ($follow)
+{
+	$follow = "-follow";
+}
+else
+{
+	$follow = "";
+}
+
+if ($no_recursion)
+{
+	$maxdepth = "-maxdepth 1";
+}
+else
+{
+	$maxdepth = "";
+}
+
+# Check for valid options
+check_options();
+
+# Only --extract, --remove and --diff allow unnamed parameters
+if (@ARGV && !($extract || $remove || $diff || @opt_summary))
+{
+	die("Extra parameter found: '".join(" ", @ARGV)."'\n".
+	    "Use $tool_name --help to get usage information\n");
+}
+
+# Check for output filename
+$data_stdout = !($output_filename && ($output_filename ne "-"));
+
+if ($capture)
+{
+	if ($data_stdout)
+	{
+		# Option that tells geninfo to write to stdout
+		$output_filename = "-";
+	}
+}
+
+# Determine kernel directory for gcov data
+if (!$from_package && !@directory && ($capture || $reset)) {
+	($gcov_gkv, $gcov_dir) = setup_gkv();
+}
+
+# Check for requested functionality
+if ($reset)
+{
+	$data_stdout = 0;
+	# Differentiate between user space and kernel reset
+	if (@directory)
+	{
+		userspace_reset();
+	}
+	else
+	{
+		kernel_reset();
+	}
+}
+elsif ($capture)
+{
+	# Capture source can be user space, kernel or package
+	if ($from_package) {
+		package_capture();
+	} elsif (@directory) {
+		userspace_capture();
+	} else {
+		if ($initial) {
+			if (defined($to_package)) {
+				die("ERROR: --initial cannot be used together ".
+				    "with --to-package\n");
+			}
+			kernel_capture_initial();
+		} else {
+			kernel_capture();
+		}
+	}
+}
+elsif (@add_tracefile)
+{
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = add_traces();
+}
+elsif ($remove)
+{
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = remove();
+}
+elsif ($extract)
+{
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = extract();
+}
+elsif ($list)
+{
+	$data_stdout = 0;
+	list();
+}
+elsif ($diff)
+{
+	if (scalar(@ARGV) != 1)
+	{
+		die("ERROR: option --diff requires one additional argument!\n".
+		    "Use $tool_name --help to get usage information\n");
+	}
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = diff();
+}
+elsif (@opt_summary)
+{
+	$data_stdout = 0;
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = summary();
+}
+
+temp_cleanup();
+
+if (defined($ln_overall_found)) {
+	print_overall_rate(1, $ln_overall_found, $ln_overall_hit,
+			   1, $fn_overall_found, $fn_overall_hit,
+			   1, $br_overall_found, $br_overall_hit);
+} else {
+	info("Done.\n") if (!$list && !$capture);
+}
+exit(0);
+
+#
+# print_usage(handle)
+#
+# Print usage information.
+#
+
+sub print_usage(*)
+{
+	local *HANDLE = $_[0];
+
+	print(HANDLE <<END_OF_USAGE);
+Usage: $tool_name [OPTIONS]
+
+Use lcov to collect coverage data from either the currently running Linux
+kernel or from a user space application. Specify the --directory option to
+get coverage data for a user space program.
+
+Misc:
+  -h, --help                      Print this help, then exit
+  -v, --version                   Print version number, then exit
+  -q, --quiet                     Do not print progress messages
+
+Operation:
+  -z, --zerocounters              Reset all execution counts to zero
+  -c, --capture                   Capture coverage data
+  -a, --add-tracefile FILE        Add contents of tracefiles
+  -e, --extract FILE PATTERN      Extract files matching PATTERN from FILE
+  -r, --remove FILE PATTERN       Remove files matching PATTERN from FILE
+  -l, --list FILE                 List contents of tracefile FILE
+      --diff FILE DIFF            Transform tracefile FILE according to DIFF
+      --summary FILE              Show summary coverage data for tracefiles
+
+Options:
+  -i, --initial                   Capture initial zero coverage data
+  -t, --test-name NAME            Specify test name to be stored with data
+  -o, --output-file FILENAME      Write data to FILENAME instead of stdout
+  -d, --directory DIR             Use .da files in DIR instead of kernel
+  -f, --follow                    Follow links when searching .da files
+  -k, --kernel-directory KDIR     Capture kernel coverage data only from KDIR
+  -b, --base-directory DIR        Use DIR as base directory for relative paths
+      --convert-filenames         Convert filenames when applying diff
+      --strip DEPTH               Strip initial DEPTH directory levels in diff
+      --path PATH                 Strip PATH from tracefile when applying diff
+      --(no-)checksum             Enable (disable) line checksumming
+      --(no-)compat-libtool       Enable (disable) libtool compatibility mode
+      --gcov-tool TOOL            Specify gcov tool location
+      --ignore-errors ERRORS      Continue after ERRORS (gcov, source, graph)
+      --no-recursion              Exclude subdirectories from processing
+      --to-package FILENAME       Store unprocessed coverage data in FILENAME
+      --from-package FILENAME     Capture from unprocessed data in FILENAME
+      --no-markers                Ignore exclusion markers in source code
+      --derive-func-data          Generate function data from line data
+      --list-full-path            Print full path during a list operation
+      --(no-)external             Include (ignore) data for external files
+      --config-file FILENAME      Specify configuration file location
+      --rc SETTING=VALUE          Override configuration file setting
+      --compat MODE=on|off|auto   Set compat MODE (libtool, hammer, split_crc)
+      --include PATTERN           Include files matching PATTERN
+      --exclude PATTERN           Exclude files matching PATTERN
+
+For more information see: $lcov_url
+END_OF_USAGE
+	;
+}
+
+
+#
+# check_options()
+#
+# Check for valid combination of command line options. Die on error.
+#
+
+sub check_options()
+{
+	my $i = 0;
+
+	# Count occurrence of mutually exclusive options
+	$reset && $i++;
+	$capture && $i++;
+	@add_tracefile && $i++;
+	$extract && $i++;
+	$remove && $i++;
+	$list && $i++;
+	$diff && $i++;
+	@opt_summary && $i++;
+	
+	if ($i == 0)
+	{
+		die("Need one of options -z, -c, -a, -e, -r, -l, ".
+		    "--diff or --summary\n".
+		    "Use $tool_name --help to get usage information\n");
+	}
+	elsif ($i > 1)
+	{
+		die("ERROR: only one of -z, -c, -a, -e, -r, -l, ".
+		    "--diff or --summary allowed!\n".
+		    "Use $tool_name --help to get usage information\n");
+	}
+}
+
+
+#
+# userspace_reset()
+#
+# Reset coverage data found in DIRECTORY by deleting all contained .da files.
+#
+# Die on error.
+#
+
+sub userspace_reset()
+{
+	my $current_dir;
+	my @file_list;
+
+	foreach $current_dir (@directory)
+	{
+		info("Deleting all .da files in $current_dir".
+		     ($no_recursion?"\n":" and subdirectories\n"));
+		@file_list = `find "$current_dir" $maxdepth $follow -name \\*\\.da -type f -o -name \\*\\.gcda -type f 2>/dev/null`;
+		chomp(@file_list);
+		foreach (@file_list)
+		{
+			unlink($_) or die("ERROR: cannot remove file $_!\n");
+		}
+	}
+}
+
+
+#
+# userspace_capture()
+#
+# Capture coverage data found in DIRECTORY and write it to a package (if
+# TO_PACKAGE specified) or to OUTPUT_FILENAME or STDOUT.
+#
+# Die on error.
+#
+
+sub userspace_capture()
+{
+	my $dir;
+	my $build;
+
+	if (!defined($to_package)) {
+		lcov_geninfo(@directory);
+		return;
+	}
+	if (scalar(@directory) != 1) {
+		die("ERROR: -d may be specified only once with --to-package\n");
+	}
+	$dir = $directory[0];
+	if (defined($base_directory)) {
+		$build = $base_directory;
+	} else {
+		$build = $dir;
+	}
+	create_package($to_package, $dir, $build);
+}
+
+
+#
+# kernel_reset()
+#
+# Reset kernel coverage.
+#
+# Die on error.
+#
+
+sub kernel_reset()
+{
+	local *HANDLE;
+	my $reset_file;
+
+	info("Resetting kernel execution counters\n");
+	if (-e "$gcov_dir/vmlinux") {
+		$reset_file = "$gcov_dir/vmlinux";
+	} elsif (-e "$gcov_dir/reset") {
+		$reset_file = "$gcov_dir/reset";
+	} else {
+		die("ERROR: no reset control found in $gcov_dir\n");
+	}
+	open(HANDLE, ">", $reset_file) or
+		die("ERROR: cannot write to $reset_file!\n");
+	print(HANDLE "0");
+	close(HANDLE);
+}
+
+
+#
+# lcov_copy_single(from, to)
+# 
+# Copy single regular file FROM to TO without checking its size. This is
+# required to work with special files generated by the kernel
+# seq_file-interface.
+#
+#
+sub lcov_copy_single($$)
+{
+	my ($from, $to) = @_;
+	my $content;
+	local $/;
+	local *HANDLE;
+
+	open(HANDLE, "<", $from) or die("ERROR: cannot read $from: $!\n");
+	$content = <HANDLE>;
+	close(HANDLE);
+	open(HANDLE, ">", $to) or die("ERROR: cannot write $from: $!\n");
+	if (defined($content)) {
+		print(HANDLE $content);
+	}
+	close(HANDLE);
+}
+
+#
+# lcov_find(dir, function, data[, extension, ...)])
+#
+# Search DIR for files and directories whose name matches PATTERN and run
+# FUNCTION for each match. If not pattern is specified, match all names.
+#
+# FUNCTION has the following prototype:
+#   function(dir, relative_name, data)
+#
+# Where:
+#   dir: the base directory for this search
+#   relative_name: the name relative to the base directory of this entry
+#   data: the DATA variable passed to lcov_find
+#
+sub lcov_find($$$;@)
+{
+	my ($dir, $fn, $data, @pattern) = @_;
+	my $result;
+	my $_fn = sub {
+		my $filename = $File::Find::name;
+
+		if (defined($result)) {
+			return;
+		}		
+		$filename = abs2rel($filename, $dir);
+		foreach (@pattern) {
+			if ($filename =~ /$_/) {
+				goto ok;
+			}
+		}
+		return;
+	ok:
+		$result = &$fn($dir, $filename, $data);
+	};
+	if (scalar(@pattern) == 0) {
+		@pattern = ".*";
+	}
+	find( { wanted => $_fn, no_chdir => 1 }, $dir);
+
+	return $result;
+}
+
+#
+# lcov_copy_fn(from, rel, to)
+#
+# Copy directories, files and links from/rel to to/rel.
+#
+
+sub lcov_copy_fn($$$)
+{
+	my ($from, $rel, $to) = @_;
+	my $absfrom = canonpath(catfile($from, $rel));
+	my $absto = canonpath(catfile($to, $rel));
+
+	if (-d) {
+		if (! -d $absto) {
+			mkpath($absto) or
+				die("ERROR: cannot create directory $absto\n");
+			chmod(0700, $absto);
+		}
+	} elsif (-l) {
+		# Copy symbolic link
+		my $link = readlink($absfrom);
+
+		if (!defined($link)) {
+			die("ERROR: cannot read link $absfrom: $!\n");
+		}
+		symlink($link, $absto) or
+			die("ERROR: cannot create link $absto: $!\n");
+	} else {
+		lcov_copy_single($absfrom, $absto);
+		chmod(0600, $absto);
+	}
+	return undef;
+}
+
+#
+# lcov_copy(from, to, subdirs)
+# 
+# Copy all specified SUBDIRS and files from directory FROM to directory TO. For
+# regular files, copy file contents without checking its size. This is required
+# to work with seq_file-generated files.
+#
+
+sub lcov_copy($$;@)
+{
+	my ($from, $to, @subdirs) = @_;
+	my @pattern;
+
+	foreach (@subdirs) {
+		push(@pattern, "^$_");
+	}
+	lcov_find($from, \&lcov_copy_fn, $to, @pattern);
+}
+
+#
+# lcov_geninfo(directory)
+#
+# Call geninfo for the specified directory and with the parameters specified
+# at the command line.
+#
+
+sub lcov_geninfo(@)
+{
+	my (@dir) = @_;
+	my @param;
+
+	# Capture data
+	info("Capturing coverage data from ".join(" ", @dir)."\n");
+	@param = ("$tool_dir/geninfo", @dir);
+	if ($output_filename)
+	{
+		@param = (@param, "--output-filename", $output_filename);
+	}
+	if ($test_name)
+	{
+		@param = (@param, "--test-name", $test_name);
+	}
+	if ($follow)
+	{
+		@param = (@param, "--follow");
+	}
+	if ($quiet)
+	{
+		@param = (@param, "--quiet");
+	}
+	if (defined($checksum))
+	{
+		if ($checksum)
+		{
+			@param = (@param, "--checksum");
+		}
+		else
+		{
+			@param = (@param, "--no-checksum");
+		}
+	}
+	if ($base_directory)
+	{
+		@param = (@param, "--base-directory", $base_directory);
+	}
+	if ($no_compat_libtool)
+	{
+		@param = (@param, "--no-compat-libtool");
+	}
+	elsif ($compat_libtool)
+	{
+		@param = (@param, "--compat-libtool");
+	}
+	if ($gcov_tool)
+	{
+		@param = (@param, "--gcov-tool", $gcov_tool);
+	}
+	foreach (@opt_ignore_errors) {
+		@param = (@param, "--ignore-errors", $_);
+	}
+	if ($no_recursion) {
+		@param = (@param, "--no-recursion");
+	}
+	if ($initial)
+	{
+		@param = (@param, "--initial");
+	}
+	if ($no_markers)
+	{
+		@param = (@param, "--no-markers");
+	}
+	if ($opt_derive_func_data)
+	{
+		@param = (@param, "--derive-func-data");
+	}
+	if ($opt_debug)
+	{
+		@param = (@param, "--debug");
+	}
+	if (defined($opt_external) && $opt_external)
+	{
+		@param = (@param, "--external");
+	}
+	if (defined($opt_external) && !$opt_external)
+	{
+		@param = (@param, "--no-external");
+	}
+	if (defined($opt_compat)) {
+		@param = (@param, "--compat", $opt_compat);
+	}
+	if (%opt_rc) {
+		foreach my $key (keys(%opt_rc)) {
+			@param = (@param, "--rc", "$key=".$opt_rc{$key});
+		}
+	}
+	if (defined($opt_config_file)) {
+		@param = (@param, "--config-file", $opt_config_file);
+	}
+	foreach (@include_patterns) {
+		@param = (@param, "--include", $_);
+	}
+	foreach (@exclude_patterns) {
+		@param = (@param, "--exclude", $_);
+	}
+
+	system(@param) and exit($? >> 8);
+}
+
+#
+# read_file(filename)
+#
+# Return the contents of the file defined by filename.
+#
+
+sub read_file($)
+{
+	my ($filename) = @_;
+	my $content;
+	local $\;
+	local *HANDLE;
+
+	open(HANDLE, "<", $filename) || return undef;
+	$content = <HANDLE>;
+	close(HANDLE);
+
+	return $content;
+}
+
+#
+# get_package(package_file)
+#
+# Unpack unprocessed coverage data files from package_file to a temporary
+# directory and return directory name, build directory and gcov kernel version
+# as found in package.
+#
+
+sub get_package($)
+{
+	my ($file) = @_;
+	my $dir = create_temp_dir();
+	my $gkv;
+	my $build;
+	my $cwd = getcwd();
+	my $count;
+	local *HANDLE;
+
+	info("Reading package $file:\n");
+	$file = abs_path($file);
+	chdir($dir);
+	open(HANDLE, "-|", "tar xvfz '$file' 2>/dev/null")
+		or die("ERROR: could not process package $file\n");
+	$count = 0;
+	while (<HANDLE>) {
+		if (/\.da$/ || /\.gcda$/) {
+			$count++;
+		}
+	}
+	close(HANDLE);
+	if ($count == 0) {
+		die("ERROR: no data file found in package $file\n");
+	}
+	info("  data directory .......: $dir\n");
+	$build = read_file("$dir/$pkg_build_file");
+	if (defined($build)) {
+		info("  build directory ......: $build\n");
+	}
+	$gkv = read_file("$dir/$pkg_gkv_file");
+	if (defined($gkv)) {
+		$gkv = int($gkv);
+		if ($gkv != $GKV_PROC && $gkv != $GKV_SYS) {
+			die("ERROR: unsupported gcov kernel version found ".
+			    "($gkv)\n");
+		}
+		info("  content type .........: kernel data\n");
+		info("  gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
+	} else {
+		info("  content type .........: application data\n");
+	}
+	info("  data files ...........: $count\n");
+	chdir($cwd);
+
+	return ($dir, $build, $gkv);
+}
+
+#
+# write_file(filename, $content)
+#
+# Create a file named filename and write the specified content to it.
+#
+
+sub write_file($$)
+{
+	my ($filename, $content) = @_;
+	local *HANDLE;
+
+	open(HANDLE, ">", $filename) || return 0;
+	print(HANDLE $content);
+	close(HANDLE) || return 0;
+
+	return 1;
+}
+
+# count_package_data(filename)
+#
+# Count the number of coverage data files in the specified package file.
+#
+
+sub count_package_data($)
+{
+	my ($filename) = @_;
+	local *HANDLE;
+	my $count = 0;
+
+	open(HANDLE, "-|", "tar tfz '$filename'") or return undef;
+	while (<HANDLE>) {
+		if (/\.da$/ || /\.gcda$/) {
+			$count++;
+		}
+	}
+	close(HANDLE);
+	return $count;
+}
+
+#
+# create_package(package_file, source_directory, build_directory[,
+# 		 kernel_gcov_version])
+#
+# Store unprocessed coverage data files from source_directory to package_file.
+#
+
+sub create_package($$$;$)
+{
+	my ($file, $dir, $build, $gkv) = @_;
+	my $cwd = getcwd();
+
+	# Check for availability of tar tool first
+	system("tar --help > /dev/null")
+		and die("ERROR: tar command not available\n");
+
+	# Print information about the package
+	info("Creating package $file:\n");
+	info("  data directory .......: $dir\n");
+
+	# Handle build directory
+	if (defined($build)) {
+		info("  build directory ......: $build\n");
+		write_file("$dir/$pkg_build_file", $build)
+			or die("ERROR: could not write to ".
+			       "$dir/$pkg_build_file\n");
+	}
+
+	# Handle gcov kernel version data
+	if (defined($gkv)) {
+		info("  content type .........: kernel data\n");
+		info("  gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
+		write_file("$dir/$pkg_gkv_file", $gkv)
+			or die("ERROR: could not write to ".
+			       "$dir/$pkg_gkv_file\n");
+	} else {
+		info("  content type .........: application data\n");
+	}
+
+	# Create package
+	$file = abs_path($file);
+	chdir($dir);
+	system("tar cfz $file .")
+		and die("ERROR: could not create package $file\n");
+	chdir($cwd);
+
+	# Remove temporary files
+	unlink("$dir/$pkg_build_file");
+	unlink("$dir/$pkg_gkv_file");
+
+	# Show number of data files
+	if (!$quiet) {
+		my $count = count_package_data($file);
+
+		if (defined($count)) {
+			info("  data files ...........: $count\n");
+		}
+	}
+}
+
+sub find_link_fn($$$)
+{
+	my ($from, $rel, $filename) = @_;
+	my $absfile = catfile($from, $rel, $filename);
+
+	if (-l $absfile) {
+		return $absfile;
+	}
+	return undef;
+}
+
+#
+# get_base(dir)
+#
+# Return (BASE, OBJ), where
+#  - BASE: is the path to the kernel base directory relative to dir
+#  - OBJ: is the absolute path to the kernel build directory
+#
+
+sub get_base($)
+{
+	my ($dir) = @_;
+	my $marker = "kernel/gcov/base.gcno";
+	my $markerfile;
+	my $sys;
+	my $obj;
+	my $link;
+
+	$markerfile = lcov_find($dir, \&find_link_fn, $marker);
+	if (!defined($markerfile)) {
+		return (undef, undef);
+	}
+
+	# sys base is parent of parent of markerfile.
+	$sys = abs2rel(dirname(dirname(dirname($markerfile))), $dir);
+
+	# obj base is parent of parent of markerfile link target.
+	$link = readlink($markerfile);
+	if (!defined($link)) {
+		die("ERROR: could not read $markerfile\n");
+	}
+	$obj = dirname(dirname(dirname($link)));
+
+	return ($sys, $obj);
+}
+
+#
+# apply_base_dir(data_dir, base_dir, build_dir, @directories)
+#
+# Make entries in @directories relative to data_dir.
+#
+
+sub apply_base_dir($$$@)
+{
+	my ($data, $base, $build, @dirs) = @_;
+	my $dir;
+	my @result;
+
+	foreach $dir (@dirs) {
+		# Is directory path relative to data directory?
+		if (-d catdir($data, $dir)) {
+			push(@result, $dir);
+			next;
+		}
+		# Relative to the auto-detected base-directory?
+		if (defined($base)) {
+			if (-d catdir($data, $base, $dir)) {
+				push(@result, catdir($base, $dir));
+				next;
+			}
+		}
+		# Relative to the specified base-directory?
+		if (defined($base_directory)) {
+			if (file_name_is_absolute($base_directory)) {
+				$base = abs2rel($base_directory, rootdir());
+			} else {
+				$base = $base_directory;
+			}
+			if (-d catdir($data, $base, $dir)) {
+				push(@result, catdir($base, $dir));
+				next;
+			}
+		}
+		# Relative to the build directory?
+		if (defined($build)) {
+			if (file_name_is_absolute($build)) {
+				$base = abs2rel($build, rootdir());
+			} else {
+				$base = $build;
+			}
+			if (-d catdir($data, $base, $dir)) {
+				push(@result, catdir($base, $dir));
+				next;
+			}
+		}
+		die("ERROR: subdirectory $dir not found\n".
+		    "Please use -b to specify the correct directory\n");
+	}
+	return @result;
+}
+
+#
+# copy_gcov_dir(dir, [@subdirectories])
+#
+# Create a temporary directory and copy all or, if specified, only some
+# subdirectories from dir to that directory. Return the name of the temporary
+# directory.
+#
+
+sub copy_gcov_dir($;@)
+{
+	my ($data, @dirs) = @_;
+	my $tempdir = create_temp_dir();
+
+	info("Copying data to temporary directory $tempdir\n");
+	lcov_copy($data, $tempdir, @dirs);
+
+	return $tempdir;
+}
+
+#
+# kernel_capture_initial
+#
+# Capture initial kernel coverage data, i.e. create a coverage data file from
+# static graph files which contains zero coverage data for all instrumented
+# lines.
+#
+
+sub kernel_capture_initial()
+{
+	my $build;
+	my $source;
+	my @params;
+
+	if (defined($base_directory)) {
+		$build = $base_directory;
+		$source = "specified";
+	} else {
+		(undef, $build) = get_base($gcov_dir);
+		if (!defined($build)) {
+			die("ERROR: could not auto-detect build directory.\n".
+			    "Please use -b to specify the build directory\n");
+		}
+		$source = "auto-detected";
+	}
+	info("Using $build as kernel build directory ($source)\n");
+	# Build directory needs to be passed to geninfo
+	$base_directory = $build;
+	if (@kernel_directory) {
+		foreach my $dir (@kernel_directory) {
+			push(@params, "$build/$dir");
+		}
+	} else {
+		push(@params, $build);
+	}
+	lcov_geninfo(@params);
+}
+
+#
+# kernel_capture_from_dir(directory, gcov_kernel_version, build)
+#
+# Perform the actual kernel coverage capturing from the specified directory
+# assuming that the data was copied from the specified gcov kernel version.
+#
+
+sub kernel_capture_from_dir($$$)
+{
+	my ($dir, $gkv, $build) = @_;
+
+	# Create package or coverage file
+	if (defined($to_package)) {
+		create_package($to_package, $dir, $build, $gkv);
+	} else {
+		# Build directory needs to be passed to geninfo
+		$base_directory = $build;
+		lcov_geninfo($dir);
+	}
+}
+
+#
+# adjust_kernel_dir(dir, build)
+#
+# Adjust directories specified with -k so that they point to the directory
+# relative to DIR. Return the build directory if specified or the auto-
+# detected build-directory.
+#
+
+sub adjust_kernel_dir($$)
+{
+	my ($dir, $build) = @_;
+	my ($sys_base, $build_auto) = get_base($dir);
+
+	if (!defined($build)) {
+		$build = $build_auto;
+	}
+	if (!defined($build)) {
+		die("ERROR: could not auto-detect build directory.\n".
+		    "Please use -b to specify the build directory\n");
+	}
+	# Make @kernel_directory relative to sysfs base
+	if (@kernel_directory) {
+		@kernel_directory = apply_base_dir($dir, $sys_base, $build,
+						   @kernel_directory);
+	}
+	return $build;
+}
+
+sub kernel_capture()
+{
+	my $data_dir;
+	my $build = $base_directory;
+
+	if ($gcov_gkv == $GKV_SYS) {
+		$build = adjust_kernel_dir($gcov_dir, $build);
+	}
+	$data_dir = copy_gcov_dir($gcov_dir, @kernel_directory);
+	kernel_capture_from_dir($data_dir, $gcov_gkv, $build);
+}
+
+#
+# link_data_cb(datadir, rel, graphdir)
+#
+# Create symbolic link in GRAPDIR/REL pointing to DATADIR/REL.
+#
+
+sub link_data_cb($$$)
+{
+	my ($datadir, $rel, $graphdir) = @_;
+	my $absfrom = catfile($datadir, $rel);
+	my $absto = catfile($graphdir, $rel);
+	my $base;
+	my $dir;
+
+	if (-e $absto) {
+		die("ERROR: could not create symlink at $absto: ".
+		    "File already exists!\n");
+	}
+	if (-l $absto) {
+		# Broken link - possibly from an interrupted earlier run
+		unlink($absto);
+	}
+
+	# Check for graph file
+	$base = $absto;
+	$base =~ s/\.(gcda|da)$//;
+	if (! -e $base.".gcno" && ! -e $base.".bbg" && ! -e $base.".bb") {
+		die("ERROR: No graph file found for $absfrom in ".
+		    dirname($base)."!\n");
+	}
+
+	symlink($absfrom, $absto) or
+		die("ERROR: could not create symlink at $absto: $!\n");
+}
+
+#
+# unlink_data_cb(datadir, rel, graphdir)
+#
+# Remove symbolic link from GRAPHDIR/REL to DATADIR/REL.
+#
+
+sub unlink_data_cb($$$)
+{
+	my ($datadir, $rel, $graphdir) = @_;
+	my $absfrom = catfile($datadir, $rel);
+	my $absto = catfile($graphdir, $rel);
+	my $target;
+
+	return if (!-l $absto);
+	$target = readlink($absto);
+	return if (!defined($target) || $target ne $absfrom);
+
+	unlink($absto) or
+		warn("WARNING: could not remove symlink $absto: $!\n");
+}
+
+#
+# link_data(datadir, graphdir, create)
+#
+# If CREATE is non-zero, create symbolic links in GRAPHDIR for data files
+# found in DATADIR. Otherwise remove link in GRAPHDIR.
+#
+
+sub link_data($$$)
+{
+	my ($datadir, $graphdir, $create) = @_;
+
+	$datadir = abs_path($datadir);
+	$graphdir = abs_path($graphdir);
+	if ($create) {
+		lcov_find($datadir, \&link_data_cb, $graphdir, '\.gcda$',
+			  '\.da$');
+	} else {
+		lcov_find($datadir, \&unlink_data_cb, $graphdir, '\.gcda$',
+			  '\.da$');
+	}
+}
+
+#
+# find_graph_cb(datadir, rel, count_ref)
+#
+# Count number of files found.
+#
+
+sub find_graph_cb($$$)
+{
+	my ($dir, $rel, $count_ref) = @_;
+
+	($$count_ref)++;
+}
+
+#
+# find_graph(dir)
+#
+# Search DIR for a graph file. Return non-zero if one was found, zero otherwise.
+#
+
+sub find_graph($)
+{
+	my ($dir) = @_;
+	my $count = 0;
+
+	lcov_find($dir, \&find_graph_cb, \$count, '\.gcno$', '\.bb$', '\.bbg$');
+
+	return $count > 0 ? 1 : 0;
+}
+
+#
+# package_capture()
+#
+# Capture coverage data from a package of unprocessed coverage data files
+# as generated by lcov --to-package.
+#
+
+sub package_capture()
+{
+	my $dir;
+	my $build;
+	my $gkv;
+
+	($dir, $build, $gkv) = get_package($from_package);
+
+	# Check for build directory
+	if (defined($base_directory)) {
+		if (defined($build)) {
+			info("Using build directory specified by -b.\n");
+		}
+		$build = $base_directory;
+	}
+
+	# Do the actual capture
+	if (defined($gkv)) {
+		if ($gkv == $GKV_SYS) {
+			$build = adjust_kernel_dir($dir, $build);
+		}
+		if (@kernel_directory) {
+			$dir = copy_gcov_dir($dir, @kernel_directory);	
+		}
+		kernel_capture_from_dir($dir, $gkv, $build);
+	} else {
+		# Build directory needs to be passed to geninfo
+		$base_directory = $build;
+		if (find_graph($dir)) {
+			# Package contains graph files - collect from there
+			lcov_geninfo($dir);
+		} else {
+			# No graph files found, link data files next to
+			# graph files
+			link_data($dir, $base_directory, 1);
+			lcov_geninfo($base_directory);
+			link_data($dir, $base_directory, 0);
+		}
+	}
+}
+
+
+#
+# info(printf_parameter)
+#
+# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
+# is not set.
+#
+
+sub info(@)
+{
+	if (!$quiet)
+	{
+		# Print info string
+		if (!$data_stdout)
+		{
+			printf(@_)
+		}
+		else
+		{
+			# Don't interfere with the .info output to STDOUT
+			printf(STDERR @_);
+		}
+	}
+}
+
+
+#
+# create_temp_dir()
+#
+# Create a temporary directory and return its path.
+#
+# Die on error.
+#
+
+sub create_temp_dir()
+{
+	my $dir;
+
+	if (defined($tmp_dir)) {
+		$dir = tempdir(DIR => $tmp_dir, CLEANUP => 1);
+	} else {
+		$dir = tempdir(CLEANUP => 1);
+	}
+	if (!defined($dir)) {
+		die("ERROR: cannot create temporary directory\n");
+	}
+	push(@temp_dirs, $dir);
+
+	return $dir;
+}
+
+sub compress_brcount($)
+{
+	my ($brcount) = @_;
+	my $db;
+
+	$db = brcount_to_db($brcount);
+	return db_to_brcount($db, $brcount);
+}
+
+sub get_br_found_and_hit($)
+{
+	my ($brcount) = @_;
+	my $db;
+
+	$db = brcount_to_db($brcount);
+
+	return brcount_db_get_found_and_hit($db);
+}
+
+
+#
+# read_info_file(info_filename)
+#
+# Read in the contents of the .info file specified by INFO_FILENAME. Data will
+# be returned as a reference to a hash containing the following mappings:
+#
+# %result: for each filename found in file -> \%data
+#
+# %data: "test"  -> \%testdata
+#        "sum"   -> \%sumcount
+#        "func"  -> \%funcdata
+#        "found" -> $lines_found (number of instrumented lines found in file)
+#	 "hit"   -> $lines_hit (number of executed lines in file)
+#        "f_found" -> $fn_found (number of instrumented functions found in file)
+#	 "f_hit"   -> $fn_hit (number of executed functions in file)
+#        "b_found" -> $br_found (number of instrumented branches found in file)
+#	 "b_hit"   -> $br_hit (number of executed branches in file)
+#        "check" -> \%checkdata
+#        "testfnc" -> \%testfncdata
+#        "sumfnc"  -> \%sumfnccount
+#        "testbr"  -> \%testbrdata
+#        "sumbr"   -> \%sumbrcount
+#
+# %testdata   : name of test affecting this file -> \%testcount
+# %testfncdata: name of test affecting this file -> \%testfnccount
+# %testbrdata:  name of test affecting this file -> \%testbrcount
+#
+# %testcount   : line number   -> execution count for a single test
+# %testfnccount: function name -> execution count for a single test
+# %testbrcount : line number   -> branch coverage data for a single test
+# %sumcount    : line number   -> execution count for all tests
+# %sumfnccount : function name -> execution count for all tests
+# %sumbrcount  : line number   -> branch coverage data for all tests
+# %funcdata    : function name -> line number
+# %checkdata   : line number   -> checksum of source code line
+# $brdata      : text "block,branch,taken:..."
+# 
+# Note that .info file sections referring to the same file and test name
+# will automatically be combined by adding all execution counts.
+#
+# Note that if INFO_FILENAME ends with ".gz", it is assumed that the file
+# is compressed using GZIP. If available, GUNZIP will be used to decompress
+# this file.
+#
+# Die on error.
+#
+
+sub read_info_file($)
+{
+	my $tracefile = $_[0];		# Name of tracefile
+	my %result;			# Resulting hash: file -> data
+	my $data;			# Data handle for current entry
+	my $testdata;			#       "             "
+	my $testcount;			#       "             "
+	my $sumcount;			#       "             "
+	my $funcdata;			#       "             "
+	my $checkdata;			#       "             "
+	my $testfncdata;
+	my $testfnccount;
+	my $sumfnccount;
+	my $testbrdata;
+	my $testbrcount;
+	my $sumbrcount;
+	my $line;			# Current line read from .info file
+	my $testname;			# Current test name
+	my $filename;			# Current filename
+	my $hitcount;			# Count for lines hit
+	my $count;			# Execution count of current line
+	my $negative;			# If set, warn about negative counts
+	my $changed_testname;		# If set, warn about changed testname
+	my $line_checksum;		# Checksum of current line
+	local *INFO_HANDLE;		# Filehandle for .info file
+
+	info("Reading tracefile $tracefile\n");
+
+	# Check if file exists and is readable
+	stat($_[0]);
+	if (!(-r _))
+	{
+		die("ERROR: cannot read file $_[0]!\n");
+	}
+
+	# Check if this is really a plain file
+	if (!(-f _))
+	{
+		die("ERROR: not a plain file: $_[0]!\n");
+	}
+
+	# Check for .gz extension
+	if ($_[0] =~ /\.gz$/)
+	{
+		# Check for availability of GZIP tool
+		system_no_output(1, "gunzip" ,"-h")
+			and die("ERROR: gunzip command not available!\n");
+
+		# Check integrity of compressed file
+		system_no_output(1, "gunzip", "-t", $_[0])
+			and die("ERROR: integrity check failed for ".
+				"compressed file $_[0]!\n");
+
+		# Open compressed file
+		open(INFO_HANDLE, "-|", "gunzip -c '$_[0]'")
+			or die("ERROR: cannot start gunzip to decompress ".
+			       "file $_[0]!\n");
+	}
+	else
+	{
+		# Open decompressed file
+		open(INFO_HANDLE, "<", $_[0])
+			or die("ERROR: cannot read file $_[0]!\n");
+	}
+
+	$testname = "";
+	while (<INFO_HANDLE>)
+	{
+		chomp($_);
+		$line = $_;
+
+		# Switch statement
+		foreach ($line)
+		{
+			/^TN:([^,]*)(,diff)?/ && do
+			{
+				# Test name information found
+				$testname = defined($1) ? $1 : "";
+				if ($testname =~ s/\W/_/g)
+				{
+					$changed_testname = 1;
+				}
+				$testname .= $2 if (defined($2));
+				last;
+			};
+
+			/^[SK]F:(.*)/ && do
+			{
+				# Filename information found
+				# Retrieve data for new entry
+				$filename = $1;
+
+				$data = $result{$filename};
+				($testdata, $sumcount, $funcdata, $checkdata,
+				 $testfncdata, $sumfnccount, $testbrdata,
+				 $sumbrcount) =
+					get_info_entry($data);
+
+				if (defined($testname))
+				{
+					$testcount = $testdata->{$testname};
+					$testfnccount = $testfncdata->{$testname};
+					$testbrcount = $testbrdata->{$testname};
+				}
+				else
+				{
+					$testcount = {};
+					$testfnccount = {};
+					$testbrcount = {};
+				}
+				last;
+			};
+
+			/^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do
+			{
+				# Fix negative counts
+				$count = $2 < 0 ? 0 : $2;
+				if ($2 < 0)
+				{
+					$negative = 1;
+				}
+				# Execution count found, add to structure
+				# Add summary counts
+				$sumcount->{$1} += $count;
+
+				# Add test-specific counts
+				if (defined($testname))
+				{
+					$testcount->{$1} += $count;
+				}
+
+				# Store line checksum if available
+				if (defined($3))
+				{
+					$line_checksum = substr($3, 1);
+
+					# Does it match a previous definition
+					if (defined($checkdata->{$1}) &&
+					    ($checkdata->{$1} ne
+					     $line_checksum))
+					{
+						die("ERROR: checksum mismatch ".
+						    "at $filename:$1\n");
+					}
+
+					$checkdata->{$1} = $line_checksum;
+				}
+				last;
+			};
+
+			/^FN:(\d+),([^,]+)/ && do
+			{
+				last if (!$func_coverage);
+
+				# Function data found, add to structure
+				$funcdata->{$2} = $1;
+
+				# Also initialize function call data
+				if (!defined($sumfnccount->{$2})) {
+					$sumfnccount->{$2} = 0;
+				}
+				if (defined($testname))
+				{
+					if (!defined($testfnccount->{$2})) {
+						$testfnccount->{$2} = 0;
+					}
+				}
+				last;
+			};
+
+			/^FNDA:(\d+),([^,]+)/ && do
+			{
+				last if (!$func_coverage);
+
+				# Function call count found, add to structure
+				# Add summary counts
+				$sumfnccount->{$2} += $1;
+
+				# Add test-specific counts
+				if (defined($testname))
+				{
+					$testfnccount->{$2} += $1;
+				}
+				last;
+			};
+
+			/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
+				# Branch coverage data found
+				my ($line, $block, $branch, $taken) =
+				   ($1, $2, $3, $4);
+
+				last if (!$br_coverage);
+				$sumbrcount->{$line} .=
+					"$block,$branch,$taken:";
+
+				# Add test-specific counts
+				if (defined($testname)) {
+					$testbrcount->{$line} .=
+						"$block,$branch,$taken:";
+				}
+				last;
+			};
+
+			/^end_of_record/ && do
+			{
+				# Found end of section marker
+				if ($filename)
+				{
+					# Store current section data
+					if (defined($testname))
+					{
+						$testdata->{$testname} =
+							$testcount;
+						$testfncdata->{$testname} =
+							$testfnccount;
+						$testbrdata->{$testname} =
+							$testbrcount;
+					}	
+
+					set_info_entry($data, $testdata,
+						       $sumcount, $funcdata,
+						       $checkdata, $testfncdata,
+						       $sumfnccount,
+						       $testbrdata,
+						       $sumbrcount);
+					$result{$filename} = $data;
+					last;
+				}
+			};
+
+			# default
+			last;
+		}
+	}
+	close(INFO_HANDLE);
+
+	# Calculate hit and found values for lines and functions of each file
+	foreach $filename (keys(%result))
+	{
+		$data = $result{$filename};
+
+		($testdata, $sumcount, undef, undef, $testfncdata,
+		 $sumfnccount, $testbrdata, $sumbrcount) =
+			get_info_entry($data);
+
+		# Filter out empty files
+		if (scalar(keys(%{$sumcount})) == 0)
+		{
+			delete($result{$filename});
+			next;
+		}
+		# Filter out empty test cases
+		foreach $testname (keys(%{$testdata}))
+		{
+			if (!defined($testdata->{$testname}) ||
+			    scalar(keys(%{$testdata->{$testname}})) == 0)
+			{
+				delete($testdata->{$testname});
+				delete($testfncdata->{$testname});
+			}
+		}
+
+		$data->{"found"} = scalar(keys(%{$sumcount}));
+		$hitcount = 0;
+
+		foreach (keys(%{$sumcount}))
+		{
+			if ($sumcount->{$_} > 0) { $hitcount++; }
+		}
+
+		$data->{"hit"} = $hitcount;
+
+		# Get found/hit values for function call data
+		$data->{"f_found"} = scalar(keys(%{$sumfnccount}));
+		$hitcount = 0;
+
+		foreach (keys(%{$sumfnccount})) {
+			if ($sumfnccount->{$_} > 0) {
+				$hitcount++;
+			}
+		}
+		$data->{"f_hit"} = $hitcount;
+
+		# Combine branch data for the same branches
+		(undef, $data->{"b_found"}, $data->{"b_hit"}) =
+			compress_brcount($sumbrcount);
+		foreach $testname (keys(%{$testbrdata})) {
+			compress_brcount($testbrdata->{$testname});
+		}
+	}
+
+	if (scalar(keys(%result)) == 0)
+	{
+		die("ERROR: no valid records found in tracefile $tracefile\n");
+	}
+	if ($negative)
+	{
+		warn("WARNING: negative counts found in tracefile ".
+		     "$tracefile\n");
+	}
+	if ($changed_testname)
+	{
+		warn("WARNING: invalid characters removed from testname in ".
+		     "tracefile $tracefile\n");
+	}
+
+	return(\%result);
+}
+
+
+#
+# get_info_entry(hash_ref)
+#
+# Retrieve data from an entry of the structure generated by read_info_file().
+# Return a list of references to hashes:
+# (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
+#  ref, testfncdata hash ref, sumfnccount hash ref, testbrdata hash ref,
+#  sumbrcount hash ref, lines found, lines hit, functions found,
+#  functions hit, branches found, branches hit)
+#
+
+sub get_info_entry($)
+{
+	my $testdata_ref = $_[0]->{"test"};
+	my $sumcount_ref = $_[0]->{"sum"};
+	my $funcdata_ref = $_[0]->{"func"};
+	my $checkdata_ref = $_[0]->{"check"};
+	my $testfncdata = $_[0]->{"testfnc"};
+	my $sumfnccount = $_[0]->{"sumfnc"};
+	my $testbrdata = $_[0]->{"testbr"};
+	my $sumbrcount = $_[0]->{"sumbr"};
+	my $lines_found = $_[0]->{"found"};
+	my $lines_hit = $_[0]->{"hit"};
+	my $f_found = $_[0]->{"f_found"};
+	my $f_hit = $_[0]->{"f_hit"};
+	my $br_found = $_[0]->{"b_found"};
+	my $br_hit = $_[0]->{"b_hit"};
+
+	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
+		$testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
+		$lines_found, $lines_hit, $f_found, $f_hit,
+		$br_found, $br_hit);
+}
+
+
+#
+# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
+#                checkdata_ref, testfncdata_ref, sumfcncount_ref,
+#                testbrdata_ref, sumbrcount_ref[,lines_found,
+#                lines_hit, f_found, f_hit, $b_found, $b_hit])
+#
+# Update the hash referenced by HASH_REF with the provided data references.
+#
+
+sub set_info_entry($$$$$$$$$;$$$$$$)
+{
+	my $data_ref = $_[0];
+
+	$data_ref->{"test"} = $_[1];
+	$data_ref->{"sum"} = $_[2];
+	$data_ref->{"func"} = $_[3];
+	$data_ref->{"check"} = $_[4];
+	$data_ref->{"testfnc"} = $_[5];
+	$data_ref->{"sumfnc"} = $_[6];
+	$data_ref->{"testbr"} = $_[7];
+	$data_ref->{"sumbr"} = $_[8];
+
+	if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
+	if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
+	if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
+	if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
+	if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
+	if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
+}
+
+
+#
+# add_counts(data1_ref, data2_ref)
+#
+# DATA1_REF and DATA2_REF are references to hashes containing a mapping
+#
+#   line number -> execution count
+#
+# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
+# is a reference to a hash containing the combined mapping in which
+# execution counts are added.
+#
+
+sub add_counts($$)
+{
+	my $data1_ref = $_[0];	# Hash 1
+	my $data2_ref = $_[1];	# Hash 2
+	my %result;		# Resulting hash
+	my $line;		# Current line iteration scalar
+	my $data1_count;	# Count of line in hash1
+	my $data2_count;	# Count of line in hash2
+	my $found = 0;		# Total number of lines found
+	my $hit = 0;		# Number of lines with a count > 0
+
+	foreach $line (keys(%$data1_ref))
+	{
+		$data1_count = $data1_ref->{$line};
+		$data2_count = $data2_ref->{$line};
+
+		# Add counts if present in both hashes
+		if (defined($data2_count)) { $data1_count += $data2_count; }
+
+		# Store sum in %result
+		$result{$line} = $data1_count;
+
+		$found++;
+		if ($data1_count > 0) { $hit++; }
+	}
+
+	# Add lines unique to data2_ref
+	foreach $line (keys(%$data2_ref))
+	{
+		# Skip lines already in data1_ref
+		if (defined($data1_ref->{$line})) { next; }
+
+		# Copy count from data2_ref
+		$result{$line} = $data2_ref->{$line};
+
+		$found++;
+		if ($result{$line} > 0) { $hit++; }
+	}
+
+	return (\%result, $found, $hit);
+}
+
+
+#
+# merge_checksums(ref1, ref2, filename)
+#
+# REF1 and REF2 are references to hashes containing a mapping
+#
+#   line number -> checksum
+#
+# Merge checksum lists defined in REF1 and REF2 and return reference to
+# resulting hash. Die if a checksum for a line is defined in both hashes
+# but does not match.
+#
+
+sub merge_checksums($$$)
+{
+	my $ref1 = $_[0];
+	my $ref2 = $_[1];
+	my $filename = $_[2];
+	my %result;
+	my $line;
+
+	foreach $line (keys(%{$ref1}))
+	{
+		if (defined($ref2->{$line}) &&
+		    ($ref1->{$line} ne $ref2->{$line}))
+		{
+			die("ERROR: checksum mismatch at $filename:$line\n");
+		}
+		$result{$line} = $ref1->{$line};
+	}
+
+	foreach $line (keys(%{$ref2}))
+	{
+		$result{$line} = $ref2->{$line};
+	}
+
+	return \%result;
+}
+
+
+#
+# merge_func_data(funcdata1, funcdata2, filename)
+#
+
+sub merge_func_data($$$)
+{
+	my ($funcdata1, $funcdata2, $filename) = @_;
+	my %result;
+	my $func;
+
+	if (defined($funcdata1)) {
+		%result = %{$funcdata1};
+	}
+
+	foreach $func (keys(%{$funcdata2})) {
+		my $line1 = $result{$func};
+		my $line2 = $funcdata2->{$func};
+
+		if (defined($line1) && ($line1 != $line2)) {
+			warn("WARNING: function data mismatch at ".
+			     "$filename:$line2\n");
+			next;
+		}
+		$result{$func} = $line2;
+	}
+
+	return \%result;
+}
+
+
+#
+# add_fnccount(fnccount1, fnccount2)
+#
+# Add function call count data. Return list (fnccount_added, f_found, f_hit)
+#
+
+sub add_fnccount($$)
+{
+	my ($fnccount1, $fnccount2) = @_;
+	my %result;
+	my $f_found;
+	my $f_hit;
+	my $function;
+
+	if (defined($fnccount1)) {
+		%result = %{$fnccount1};
+	}
+	foreach $function (keys(%{$fnccount2})) {
+		$result{$function} += $fnccount2->{$function};
+	}
+	$f_found = scalar(keys(%result));
+	$f_hit = 0;
+	foreach $function (keys(%result)) {
+		if ($result{$function} > 0) {
+			$f_hit++;
+		}
+	}
+
+	return (\%result, $f_found, $f_hit);
+}
+
+#
+# add_testfncdata(testfncdata1, testfncdata2)
+#
+# Add function call count data for several tests. Return reference to
+# added_testfncdata.
+#
+
+sub add_testfncdata($$)
+{
+	my ($testfncdata1, $testfncdata2) = @_;
+	my %result;
+	my $testname;
+
+	foreach $testname (keys(%{$testfncdata1})) {
+		if (defined($testfncdata2->{$testname})) {
+			my $fnccount;
+
+			# Function call count data for this testname exists
+			# in both data sets: merge
+			($fnccount) = add_fnccount(
+				$testfncdata1->{$testname},
+				$testfncdata2->{$testname});
+			$result{$testname} = $fnccount;
+			next;
+		}
+		# Function call count data for this testname is unique to
+		# data set 1: copy
+		$result{$testname} = $testfncdata1->{$testname};
+	}
+
+	# Add count data for testnames unique to data set 2
+	foreach $testname (keys(%{$testfncdata2})) {
+		if (!defined($result{$testname})) {
+			$result{$testname} = $testfncdata2->{$testname};
+		}
+	}
+	return \%result;
+}
+
+
+#
+# brcount_to_db(brcount)
+#
+# Convert brcount data to the following format:
+#
+# db:          line number    -> block hash
+# block hash:  block number   -> branch hash
+# branch hash: branch number  -> taken value
+#
+
+sub brcount_to_db($)
+{
+	my ($brcount) = @_;
+	my $line;
+	my $db = {};
+
+	# Add branches to database
+	foreach $line (keys(%{$brcount})) {
+		my $brdata = $brcount->{$line};
+
+		foreach my $entry (split(/:/, $brdata)) {
+			my ($block, $branch, $taken) = split(/,/, $entry);
+			my $old = $db->{$line}->{$block}->{$branch};
+
+			if (!defined($old) || $old eq "-") {
+				$old = $taken;
+			} elsif ($taken ne "-") {
+				$old += $taken;
+			}
+
+			$db->{$line}->{$block}->{$branch} = $old;
+		}
+	}
+
+	return $db;
+}
+
+
+#
+# db_to_brcount(db[, brcount])
+#
+# Convert branch coverage data back to brcount format. If brcount is specified,
+# the converted data is directly inserted in brcount.
+#
+
+sub db_to_brcount($;$)
+{
+	my ($db, $brcount) = @_;
+	my $line;
+	my $br_found = 0;
+	my $br_hit = 0;
+
+	# Convert database back to brcount format
+	foreach $line (sort({$a <=> $b} keys(%{$db}))) {
+		my $ldata = $db->{$line};
+		my $brdata;
+		my $block;
+
+		foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
+			my $bdata = $ldata->{$block};
+			my $branch;
+
+			foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
+				my $taken = $bdata->{$branch};
+
+				$br_found++;
+				$br_hit++ if ($taken ne "-" && $taken > 0);
+				$brdata .= "$block,$branch,$taken:";
+			}
+		}
+		$brcount->{$line} = $brdata;
+	}
+
+	return ($brcount, $br_found, $br_hit);
+}
+
+
+#
+# brcount_db_combine(db1, db2, op)
+#
+# db1 := db1 op db2, where
+#   db1, db2: brcount data as returned by brcount_to_db
+#   op:       one of $BR_ADD and BR_SUB
+#
+sub brcount_db_combine($$$)
+{
+	my ($db1, $db2, $op) = @_;
+
+	foreach my $line (keys(%{$db2})) {
+		my $ldata = $db2->{$line};
+
+		foreach my $block (keys(%{$ldata})) {
+			my $bdata = $ldata->{$block};
+
+			foreach my $branch (keys(%{$bdata})) {
+				my $taken = $bdata->{$branch};
+				my $new = $db1->{$line}->{$block}->{$branch};
+
+				if (!defined($new) || $new eq "-") {
+					$new = $taken;
+				} elsif ($taken ne "-") {
+					if ($op == $BR_ADD) {
+						$new += $taken;
+					} elsif ($op == $BR_SUB) {
+						$new -= $taken;
+						$new = 0 if ($new < 0);
+					}
+				}
+
+				$db1->{$line}->{$block}->{$branch} = $new;
+			}
+		}
+	}
+}
+
+
+#
+# brcount_db_get_found_and_hit(db)
+#
+# Return (br_found, br_hit) for db.
+#
+
+sub brcount_db_get_found_and_hit($)
+{
+	my ($db) = @_;
+	my ($br_found , $br_hit) = (0, 0);
+
+	foreach my $line (keys(%{$db})) {
+		my $ldata = $db->{$line};
+
+		foreach my $block (keys(%{$ldata})) {
+			my $bdata = $ldata->{$block};
+
+			foreach my $branch (keys(%{$bdata})) {
+				my $taken = $bdata->{$branch};
+
+				$br_found++;
+				$br_hit++ if ($taken ne "-" && $taken > 0);
+			}
+		}
+	}
+
+	return ($br_found, $br_hit);
+}
+
+
+# combine_brcount(brcount1, brcount2, type, inplace)
+#
+# If add is BR_ADD, add branch coverage data and return list brcount_added.
+# If add is BR_SUB, subtract the taken values of brcount2 from brcount1 and
+# return brcount_sub. If inplace is set, the result is inserted into brcount1.
+#
+
+sub combine_brcount($$$;$)
+{
+	my ($brcount1, $brcount2, $type, $inplace) = @_;
+	my ($db1, $db2);
+
+	$db1 = brcount_to_db($brcount1);
+	$db2 = brcount_to_db($brcount2);
+	brcount_db_combine($db1, $db2, $type);
+
+	return db_to_brcount($db1, $inplace ? $brcount1 : undef);
+}
+
+
+#
+# add_testbrdata(testbrdata1, testbrdata2)
+#
+# Add branch coverage data for several tests. Return reference to
+# added_testbrdata.
+#
+
+sub add_testbrdata($$)
+{
+	my ($testbrdata1, $testbrdata2) = @_;
+	my %result;
+	my $testname;
+
+	foreach $testname (keys(%{$testbrdata1})) {
+		if (defined($testbrdata2->{$testname})) {
+			my $brcount;
+
+			# Branch coverage data for this testname exists
+			# in both data sets: add
+			($brcount) = combine_brcount(
+				$testbrdata1->{$testname},
+				$testbrdata2->{$testname}, $BR_ADD);
+			$result{$testname} = $brcount;
+			next;
+		}
+		# Branch coverage data for this testname is unique to
+		# data set 1: copy
+		$result{$testname} = $testbrdata1->{$testname};
+	}
+
+	# Add count data for testnames unique to data set 2
+	foreach $testname (keys(%{$testbrdata2})) {
+		if (!defined($result{$testname})) {
+			$result{$testname} = $testbrdata2->{$testname};
+		}
+	}
+	return \%result;
+}
+
+
+#
+# combine_info_entries(entry_ref1, entry_ref2, filename)
+#
+# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
+# Return reference to resulting hash.
+#
+
+sub combine_info_entries($$$)
+{
+	my $entry1 = $_[0];	# Reference to hash containing first entry
+	my $testdata1;
+	my $sumcount1;
+	my $funcdata1;
+	my $checkdata1;
+	my $testfncdata1;
+	my $sumfnccount1;
+	my $testbrdata1;
+	my $sumbrcount1;
+
+	my $entry2 = $_[1];	# Reference to hash containing second entry
+	my $testdata2;
+	my $sumcount2;
+	my $funcdata2;
+	my $checkdata2;
+	my $testfncdata2;
+	my $sumfnccount2;
+	my $testbrdata2;
+	my $sumbrcount2;
+
+	my %result;		# Hash containing combined entry
+	my %result_testdata;
+	my $result_sumcount = {};
+	my $result_funcdata;
+	my $result_testfncdata;
+	my $result_sumfnccount;
+	my $result_testbrdata;
+	my $result_sumbrcount;
+	my $lines_found;
+	my $lines_hit;
+	my $f_found;
+	my $f_hit;
+	my $br_found;
+	my $br_hit;
+
+	my $testname;
+	my $filename = $_[2];
+
+	# Retrieve data
+	($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
+	 $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
+	($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
+	 $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
+
+	# Merge checksums
+	$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
+
+	# Combine funcdata
+	$result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename);
+
+	# Combine function call count data
+	$result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
+	($result_sumfnccount, $f_found, $f_hit) =
+		add_fnccount($sumfnccount1, $sumfnccount2);
+
+	# Combine branch coverage data
+	$result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
+	($result_sumbrcount, $br_found, $br_hit) =
+		combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
+
+	# Combine testdata
+	foreach $testname (keys(%{$testdata1}))
+	{
+		if (defined($testdata2->{$testname}))
+		{
+			# testname is present in both entries, requires
+			# combination
+			($result_testdata{$testname}) =
+				add_counts($testdata1->{$testname},
+					   $testdata2->{$testname});
+		}
+		else
+		{
+			# testname only present in entry1, add to result
+			$result_testdata{$testname} = $testdata1->{$testname};
+		}
+
+		# update sum count hash
+		($result_sumcount, $lines_found, $lines_hit) =
+			add_counts($result_sumcount,
+				   $result_testdata{$testname});
+	}
+
+	foreach $testname (keys(%{$testdata2}))
+	{
+		# Skip testnames already covered by previous iteration
+		if (defined($testdata1->{$testname})) { next; }
+
+		# testname only present in entry2, add to result hash
+		$result_testdata{$testname} = $testdata2->{$testname};
+
+		# update sum count hash
+		($result_sumcount, $lines_found, $lines_hit) =
+			add_counts($result_sumcount,
+				   $result_testdata{$testname});
+	}
+	
+	# Calculate resulting sumcount
+
+	# Store result
+	set_info_entry(\%result, \%result_testdata, $result_sumcount,
+		       $result_funcdata, $checkdata1, $result_testfncdata,
+		       $result_sumfnccount, $result_testbrdata,
+		       $result_sumbrcount, $lines_found, $lines_hit,
+		       $f_found, $f_hit, $br_found, $br_hit);
+
+	return(\%result);
+}
+
+
+#
+# combine_info_files(info_ref1, info_ref2)
+#
+# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
+# reference to resulting hash.
+#
+
+sub combine_info_files($$)
+{
+	my %hash1 = %{$_[0]};
+	my %hash2 = %{$_[1]};
+	my $filename;
+
+	foreach $filename (keys(%hash2))
+	{
+		if ($hash1{$filename})
+		{
+			# Entry already exists in hash1, combine them
+			$hash1{$filename} =
+				combine_info_entries($hash1{$filename},
+						     $hash2{$filename},
+						     $filename);
+		}
+		else
+		{
+			# Entry is unique in both hashes, simply add to
+			# resulting hash
+			$hash1{$filename} = $hash2{$filename};
+		}
+	}
+
+	return(\%hash1);
+}
+
+
+#
+# add_traces()
+#
+
+sub add_traces()
+{
+	my $total_trace;
+	my $current_trace;
+	my $tracefile;
+	my @result;
+	local *INFO_HANDLE;
+
+	info("Combining tracefiles.\n");
+
+	foreach $tracefile (@add_tracefile)
+	{
+		$current_trace = read_info_file($tracefile);
+		if ($total_trace)
+		{
+			$total_trace = combine_info_files($total_trace,
+							  $current_trace);
+		}
+		else
+		{
+			$total_trace = $current_trace;
+		}
+	}
+
+	# Write combined data
+	if (!$data_stdout)
+	{
+		info("Writing data to $output_filename\n");
+		open(INFO_HANDLE, ">", $output_filename)
+			or die("ERROR: cannot write to $output_filename!\n");
+		@result = write_info_file(*INFO_HANDLE, $total_trace);
+		close(*INFO_HANDLE);
+	}
+	else
+	{
+		@result = write_info_file(*STDOUT, $total_trace);
+	}
+
+	return @result;
+}
+
+
+#
+# write_info_file(filehandle, data)
+#
+
+sub write_info_file(*$)
+{
+	local *INFO_HANDLE = $_[0];
+	my %data = %{$_[1]};
+	my $source_file;
+	my $entry;
+	my $testdata;
+	my $sumcount;
+	my $funcdata;
+	my $checkdata;
+	my $testfncdata;
+	my $sumfnccount;
+	my $testbrdata;
+	my $sumbrcount;
+	my $testname;
+	my $line;
+	my $func;
+	my $testcount;
+	my $testfnccount;
+	my $testbrcount;
+	my $found;
+	my $hit;
+	my $f_found;
+	my $f_hit;
+	my $br_found;
+	my $br_hit;
+	my $ln_total_found = 0;
+	my $ln_total_hit = 0;
+	my $fn_total_found = 0;
+	my $fn_total_hit = 0;
+	my $br_total_found = 0;
+	my $br_total_hit = 0;
+
+	foreach $source_file (sort(keys(%data)))
+	{
+		$entry = $data{$source_file};
+		($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
+		 $sumfnccount, $testbrdata, $sumbrcount, $found, $hit,
+		 $f_found, $f_hit, $br_found, $br_hit) =
+			get_info_entry($entry);
+
+		# Add to totals
+		$ln_total_found += $found;
+		$ln_total_hit += $hit;
+		$fn_total_found += $f_found;
+		$fn_total_hit += $f_hit;
+		$br_total_found += $br_found;
+		$br_total_hit += $br_hit;
+
+		foreach $testname (sort(keys(%{$testdata})))
+		{
+			$testcount = $testdata->{$testname};
+			$testfnccount = $testfncdata->{$testname};
+			$testbrcount = $testbrdata->{$testname};
+			$found = 0;
+			$hit   = 0;
+
+			print(INFO_HANDLE "TN:$testname\n");
+			print(INFO_HANDLE "SF:$source_file\n");
+
+			# Write function related data
+			foreach $func (
+				sort({$funcdata->{$a} <=> $funcdata->{$b}}
+				keys(%{$funcdata})))
+			{
+				print(INFO_HANDLE "FN:".$funcdata->{$func}.
+				      ",$func\n");
+			}
+			foreach $func (keys(%{$testfnccount})) {
+				print(INFO_HANDLE "FNDA:".
+				      $testfnccount->{$func}.
+				      ",$func\n");
+			}
+			($f_found, $f_hit) =
+				get_func_found_and_hit($testfnccount);
+			print(INFO_HANDLE "FNF:$f_found\n");
+			print(INFO_HANDLE "FNH:$f_hit\n");
+
+			# Write branch related data
+			$br_found = 0;
+			$br_hit = 0;
+			foreach $line (sort({$a <=> $b}
+					    keys(%{$testbrcount}))) {
+				my $brdata = $testbrcount->{$line};
+
+				foreach my $brentry (split(/:/, $brdata)) {
+					my ($block, $branch, $taken) =
+						split(/,/, $brentry);
+
+					print(INFO_HANDLE "BRDA:$line,$block,".
+					      "$branch,$taken\n");
+					$br_found++;
+					$br_hit++ if ($taken ne '-' &&
+						      $taken > 0);
+				}
+			}
+			if ($br_found > 0) {
+				print(INFO_HANDLE "BRF:$br_found\n");
+				print(INFO_HANDLE "BRH:$br_hit\n");
+			}
+
+			# Write line related data
+			foreach $line (sort({$a <=> $b} keys(%{$testcount})))
+			{
+				print(INFO_HANDLE "DA:$line,".
+				      $testcount->{$line}.
+				      (defined($checkdata->{$line}) &&
+				       $checksum ?
+				       ",".$checkdata->{$line} : "")."\n");
+				$found++;
+				if ($testcount->{$line} > 0)
+				{
+					$hit++;
+				}
+
+			}
+			print(INFO_HANDLE "LF:$found\n");
+			print(INFO_HANDLE "LH:$hit\n");
+			print(INFO_HANDLE "end_of_record\n");
+		}
+	}
+
+	return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
+		$br_total_found, $br_total_hit);
+}
+
+
+#
+# transform_pattern(pattern)
+#
+# Transform shell wildcard expression to equivalent Perl regular expression.
+# Return transformed pattern.
+#
+
+sub transform_pattern($)
+{
+	my $pattern = $_[0];
+
+	# Escape special chars
+
+	$pattern =~ s/\\/\\\\/g;
+	$pattern =~ s/\//\\\//g;
+	$pattern =~ s/\^/\\\^/g;
+	$pattern =~ s/\$/\\\$/g;
+	$pattern =~ s/\(/\\\(/g;
+	$pattern =~ s/\)/\\\)/g;
+	$pattern =~ s/\[/\\\[/g;
+	$pattern =~ s/\]/\\\]/g;
+	$pattern =~ s/\{/\\\{/g;
+	$pattern =~ s/\}/\\\}/g;
+	$pattern =~ s/\./\\\./g;
+	$pattern =~ s/\,/\\\,/g;
+	$pattern =~ s/\|/\\\|/g;
+	$pattern =~ s/\+/\\\+/g;
+	$pattern =~ s/\!/\\\!/g;
+
+	# Transform ? => (.) and * => (.*)
+
+	$pattern =~ s/\*/\(\.\*\)/g;
+	$pattern =~ s/\?/\(\.\)/g;
+
+	return $pattern;
+}
+
+
+#
+# extract()
+#
+
+sub extract()
+{
+	my $data = read_info_file($extract);
+	my $filename;
+	my $keep;
+	my $pattern;
+	my @pattern_list;
+	my $extracted = 0;
+	my @result;
+	local *INFO_HANDLE;
+
+	# Need perlreg expressions instead of shell pattern
+	@pattern_list = map({ transform_pattern($_); } @ARGV);
+
+	# Filter out files which do not match any pattern
+	foreach $filename (sort(keys(%{$data})))
+	{
+		$keep = 0;
+
+		foreach $pattern (@pattern_list)
+		{
+			$keep ||= ($filename =~ (/^$pattern$/));
+		}
+
+
+		if (!$keep)
+		{
+			delete($data->{$filename});
+		}
+		else
+		{
+			info("Extracting $filename\n"),
+			$extracted++;
+		}
+	}
+
+	# Write extracted data
+	if (!$data_stdout)
+	{
+		info("Extracted $extracted files\n");
+		info("Writing data to $output_filename\n");
+		open(INFO_HANDLE, ">", $output_filename)
+			or die("ERROR: cannot write to $output_filename!\n");
+		@result = write_info_file(*INFO_HANDLE, $data);
+		close(*INFO_HANDLE);
+	}
+	else
+	{
+		@result = write_info_file(*STDOUT, $data);
+	}
+
+	return @result;
+}
+
+
+#
+# remove()
+#
+
+sub remove()
+{
+	my $data = read_info_file($remove);
+	my $filename;
+	my $match_found;
+	my $pattern;
+	my @pattern_list;
+	my $removed = 0;
+	my @result;
+	local *INFO_HANDLE;
+
+	# Need perlreg expressions instead of shell pattern
+	@pattern_list = map({ transform_pattern($_); } @ARGV);
+
+	# Filter out files that match the pattern
+	foreach $filename (sort(keys(%{$data})))
+	{
+		$match_found = 0;
+
+		foreach $pattern (@pattern_list)
+		{
+			$match_found ||= ($filename =~ (/^$pattern$/));
+		}
+
+
+		if ($match_found)
+		{
+			delete($data->{$filename});
+			info("Removing $filename\n"),
+			$removed++;
+		}
+	}
+
+	# Write data
+	if (!$data_stdout)
+	{
+		info("Deleted $removed files\n");
+		info("Writing data to $output_filename\n");
+		open(INFO_HANDLE, ">", $output_filename)
+			or die("ERROR: cannot write to $output_filename!\n");
+		@result = write_info_file(*INFO_HANDLE, $data);
+		close(*INFO_HANDLE);
+	}
+	else
+	{
+		@result = write_info_file(*STDOUT, $data);
+	}
+
+	return @result;
+}
+
+
+# get_prefix(max_width, max_percentage_too_long, path_list)
+#
+# Return a path prefix that satisfies the following requirements:
+# - is shared by more paths in path_list than any other prefix
+# - the percentage of paths which would exceed the given max_width length
+#   after applying the prefix does not exceed max_percentage_too_long
+#
+# If multiple prefixes satisfy all requirements, the longest prefix is
+# returned. Return an empty string if no prefix could be found.
+
+sub get_prefix($$@)
+{
+	my ($max_width, $max_long, @path_list) = @_;
+	my $path;
+	my $ENTRY_NUM = 0;
+	my $ENTRY_LONG = 1;
+	my %prefix;
+
+	# Build prefix hash
+	foreach $path (@path_list) {
+		my ($v, $d, $f) = splitpath($path);
+		my @dirs = splitdir($d);
+		my $p_len = length($path);
+		my $i;
+
+		# Remove trailing '/'
+		pop(@dirs) if ($dirs[scalar(@dirs) - 1] eq '');
+		for ($i = 0; $i < scalar(@dirs); $i++) {
+			my $subpath = catpath($v, catdir(@dirs[0..$i]), '');
+			my $entry = $prefix{$subpath};
+
+			$entry = [ 0, 0 ] if (!defined($entry));
+			$entry->[$ENTRY_NUM]++;
+			if (($p_len - length($subpath) - 1) > $max_width) {
+				$entry->[$ENTRY_LONG]++;
+			}
+			$prefix{$subpath} = $entry;
+		}
+	}
+	# Find suitable prefix (sort descending by two keys: 1. number of
+	# entries covered by a prefix, 2. length of prefix)
+	foreach $path (sort {($prefix{$a}->[$ENTRY_NUM] ==
+			      $prefix{$b}->[$ENTRY_NUM]) ?
+				length($b) <=> length($a) :
+				$prefix{$b}->[$ENTRY_NUM] <=>
+				$prefix{$a}->[$ENTRY_NUM]}
+				keys(%prefix)) {
+		my ($num, $long) = @{$prefix{$path}};
+
+		# Check for additional requirement: number of filenames
+		# that would be too long may not exceed a certain percentage
+		if ($long <= $num * $max_long / 100) {
+			return $path;
+		}
+	}
+
+	return "";
+}
+
+
+#
+# shorten_filename(filename, width)
+#
+# Truncate filename if it is longer than width characters.
+#
+
+sub shorten_filename($$)
+{
+	my ($filename, $width) = @_;
+	my $l = length($filename);
+	my $s;
+	my $e;
+
+	return $filename if ($l <= $width);
+	$e = int(($width - 3) / 2);
+	$s = $width - 3 - $e;
+
+	return substr($filename, 0, $s).'...'.substr($filename, $l - $e);
+}
+
+
+sub shorten_number($$)
+{
+	my ($number, $width) = @_;
+	my $result = sprintf("%*d", $width, $number);
+
+	return $result if (length($result) <= $width);
+	$number = $number / 1000;
+	return $result if (length($result) <= $width);
+	$result = sprintf("%*dk", $width - 1, $number);
+	return $result if (length($result) <= $width);
+	$number = $number / 1000;
+	$result = sprintf("%*dM", $width - 1, $number);
+	return $result if (length($result) <= $width);
+	return '#';
+}
+
+sub shorten_rate($$$)
+{
+	my ($hit, $found, $width) = @_;
+	my $result = rate($hit, $found, "%", 1, $width);
+
+	return $result if (length($result) <= $width);
+	$result = rate($hit, $found, "%", 0, $width);
+	return $result if (length($result) <= $width);
+	return "#";
+}
+
+#
+# list()
+#
+
+sub list()
+{
+	my $data = read_info_file($list);
+	my $filename;
+	my $found;
+	my $hit;
+	my $entry;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+	my $total_found = 0;
+	my $total_hit = 0;
+	my $fn_total_found = 0;
+	my $fn_total_hit = 0;
+	my $br_total_found = 0;
+	my $br_total_hit = 0;
+	my $prefix;
+	my $strlen = length("Filename");
+	my $format;
+	my $heading1;
+	my $heading2;
+	my @footer;
+	my $barlen;
+	my $rate;
+	my $fnrate;
+	my $brrate;
+	my $lastpath;
+	my $F_LN_NUM = 0;
+	my $F_LN_RATE = 1;
+	my $F_FN_NUM = 2;
+	my $F_FN_RATE = 3;
+	my $F_BR_NUM = 4;
+	my $F_BR_RATE = 5;
+	my @fwidth_narrow = (5, 5, 3, 5, 4, 5);
+	my @fwidth_wide = (6, 5, 5, 5, 6, 5);
+	my @fwidth = @fwidth_wide;
+	my $w;
+	my $max_width = $opt_list_width;
+	my $max_long = $opt_list_truncate_max;
+	my $fwidth_narrow_length;
+	my $fwidth_wide_length;
+	my $got_prefix = 0;
+	my $root_prefix = 0;
+
+	# Calculate total width of narrow fields
+	$fwidth_narrow_length = 0;
+	foreach $w (@fwidth_narrow) {
+		$fwidth_narrow_length += $w + 1;
+	}
+	# Calculate total width of wide fields
+	$fwidth_wide_length = 0;
+	foreach $w (@fwidth_wide) {
+		$fwidth_wide_length += $w + 1;
+	}
+	# Get common file path prefix
+	$prefix = get_prefix($max_width - $fwidth_narrow_length, $max_long,
+			     keys(%{$data}));
+	$root_prefix = 1 if ($prefix eq rootdir());
+	$got_prefix = 1 if (length($prefix) > 0);
+	$prefix =~ s/\/$//;
+	# Get longest filename length
+	foreach $filename (keys(%{$data})) {
+		if (!$opt_list_full_path) {
+			if (!$got_prefix || !$root_prefix &&
+			    !($filename =~ s/^\Q$prefix\/\E//)) {
+				my ($v, $d, $f) = splitpath($filename);
+
+				$filename = $f;
+			}
+		}
+		# Determine maximum length of entries
+		if (length($filename) > $strlen) {
+			$strlen = length($filename)
+		}
+	}
+	if (!$opt_list_full_path) {
+		my $blanks;
+
+		$w = $fwidth_wide_length;
+		# Check if all columns fit into max_width characters
+		if ($strlen + $fwidth_wide_length > $max_width) {
+			# Use narrow fields
+			@fwidth = @fwidth_narrow;
+			$w = $fwidth_narrow_length;
+			if (($strlen + $fwidth_narrow_length) > $max_width) {
+				# Truncate filenames at max width
+				$strlen = $max_width - $fwidth_narrow_length;
+			}
+		}
+		# Add some blanks between filename and fields if possible
+		$blanks = int($strlen * 0.5);
+		$blanks = 4 if ($blanks < 4);
+		$blanks = 8 if ($blanks > 8);
+		if (($strlen + $w + $blanks) < $max_width) {
+			$strlen += $blanks;
+		} else {
+			$strlen = $max_width - $w;
+		}
+	}
+	# Filename
+	$w = $strlen;
+	$format		= "%-${w}s|";
+	$heading1 	= sprintf("%*s|", $w, "");
+	$heading2 	= sprintf("%-*s|", $w, "Filename");
+	$barlen		= $w + 1;
+	# Line coverage rate
+	$w = $fwidth[$F_LN_RATE];
+	$format		.= "%${w}s ";
+	$heading1 	.= sprintf("%-*s |", $w + $fwidth[$F_LN_NUM],
+				   "Lines");
+	$heading2 	.= sprintf("%-*s ", $w, "Rate");
+	$barlen		+= $w + 1;
+	# Number of lines
+	$w = $fwidth[$F_LN_NUM];
+	$format		.= "%${w}s|";
+	$heading2	.= sprintf("%*s|", $w, "Num");
+	$barlen		+= $w + 1;
+	# Function coverage rate
+	$w = $fwidth[$F_FN_RATE];
+	$format		.= "%${w}s ";
+	$heading1 	.= sprintf("%-*s|", $w + $fwidth[$F_FN_NUM] + 1,
+				   "Functions");
+	$heading2 	.= sprintf("%-*s ", $w, "Rate");
+	$barlen		+= $w + 1;
+	# Number of functions
+	$w = $fwidth[$F_FN_NUM];
+	$format		.= "%${w}s|";
+	$heading2	.= sprintf("%*s|", $w, "Num");
+	$barlen		+= $w + 1;
+	# Branch coverage rate
+	$w = $fwidth[$F_BR_RATE];
+	$format		.= "%${w}s ";
+	$heading1 	.= sprintf("%-*s", $w + $fwidth[$F_BR_NUM] + 1,
+				   "Branches");
+	$heading2 	.= sprintf("%-*s ", $w, "Rate");
+	$barlen		+= $w + 1;
+	# Number of branches
+	$w = $fwidth[$F_BR_NUM];
+	$format		.= "%${w}s";
+	$heading2	.= sprintf("%*s", $w, "Num");
+	$barlen		+= $w;
+	# Line end
+	$format		.= "\n";
+	$heading1	.= "\n";
+	$heading2	.= "\n";
+
+	# Print heading
+	print($heading1);
+	print($heading2);
+	print(("="x$barlen)."\n");
+
+	# Print per file information
+	foreach $filename (sort(keys(%{$data})))
+	{
+		my @file_data;
+		my $print_filename = $filename;
+
+		$entry = $data->{$filename};
+		if (!$opt_list_full_path) {
+			my $p;
+
+			$print_filename = $filename;
+			if (!$got_prefix || !$root_prefix &&
+			    !($print_filename =~ s/^\Q$prefix\/\E//)) {
+				my ($v, $d, $f) = splitpath($filename);
+
+				$p = catpath($v, $d, "");
+				$p =~ s/\/$//;
+				$print_filename = $f;
+			} else {
+				$p = $prefix;
+			}
+
+			if (!defined($lastpath) || $lastpath ne $p) {
+				print("\n") if (defined($lastpath));
+				$lastpath = $p;
+				print("[$lastpath/]\n") if (!$root_prefix);
+			}
+			$print_filename = shorten_filename($print_filename,
+							   $strlen);
+		}
+
+		(undef, undef, undef, undef, undef, undef, undef, undef,
+		 $found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
+			get_info_entry($entry);
+
+		# Assume zero count if there is no function data for this file
+		if (!defined($fn_found) || !defined($fn_hit)) {
+			$fn_found = 0;
+			$fn_hit = 0;
+		}
+		# Assume zero count if there is no branch data for this file
+		if (!defined($br_found) || !defined($br_hit)) {
+			$br_found = 0;
+			$br_hit = 0;
+		}
+
+		# Add line coverage totals
+		$total_found += $found;
+		$total_hit += $hit;
+		# Add function coverage totals
+		$fn_total_found += $fn_found;
+		$fn_total_hit += $fn_hit;
+		# Add branch coverage totals
+		$br_total_found += $br_found;
+		$br_total_hit += $br_hit;
+
+		# Determine line coverage rate for this file
+		$rate = shorten_rate($hit, $found, $fwidth[$F_LN_RATE]);
+		# Determine function coverage rate for this file
+		$fnrate = shorten_rate($fn_hit, $fn_found, $fwidth[$F_FN_RATE]);
+		# Determine branch coverage rate for this file
+		$brrate = shorten_rate($br_hit, $br_found, $fwidth[$F_BR_RATE]);
+
+		# Assemble line parameters
+		push(@file_data, $print_filename);
+		push(@file_data, $rate);
+		push(@file_data, shorten_number($found, $fwidth[$F_LN_NUM]));
+		push(@file_data, $fnrate);
+		push(@file_data, shorten_number($fn_found, $fwidth[$F_FN_NUM]));
+		push(@file_data, $brrate);
+		push(@file_data, shorten_number($br_found, $fwidth[$F_BR_NUM]));
+
+		# Print assembled line
+		printf($format, @file_data);
+	}
+
+	# Determine total line coverage rate
+	$rate = shorten_rate($total_hit, $total_found, $fwidth[$F_LN_RATE]);
+	# Determine total function coverage rate
+	$fnrate = shorten_rate($fn_total_hit, $fn_total_found,
+			       $fwidth[$F_FN_RATE]);
+	# Determine total branch coverage rate
+	$brrate = shorten_rate($br_total_hit, $br_total_found,
+			       $fwidth[$F_BR_RATE]);
+
+	# Print separator
+	print(("="x$barlen)."\n");
+
+	# Assemble line parameters
+	push(@footer, sprintf("%*s", $strlen, "Total:"));
+	push(@footer, $rate);
+	push(@footer, shorten_number($total_found, $fwidth[$F_LN_NUM]));
+	push(@footer, $fnrate);
+	push(@footer, shorten_number($fn_total_found, $fwidth[$F_FN_NUM]));
+	push(@footer, $brrate);
+	push(@footer, shorten_number($br_total_found, $fwidth[$F_BR_NUM]));
+
+	# Print assembled line
+	printf($format, @footer);
+}
+
+
+#
+# get_common_filename(filename1, filename2)
+#
+# Check for filename components which are common to FILENAME1 and FILENAME2.
+# Upon success, return
+#
+#   (common, path1, path2)
+#
+#  or 'undef' in case there are no such parts.
+#
+
+sub get_common_filename($$)
+{
+        my @list1 = split("/", $_[0]);
+        my @list2 = split("/", $_[1]);
+	my @result;
+
+	# Work in reverse order, i.e. beginning with the filename itself
+	while (@list1 && @list2 && ($list1[$#list1] eq $list2[$#list2]))
+	{
+		unshift(@result, pop(@list1));
+		pop(@list2);
+	}
+
+	# Did we find any similarities?
+	if (scalar(@result) > 0)
+	{
+	        return (join("/", @result), join("/", @list1),
+			join("/", @list2));
+	}
+	else
+	{
+		return undef;
+	}
+}
+
+
+#
+# strip_directories($path, $depth)
+#
+# Remove DEPTH leading directory levels from PATH.
+#
+
+sub strip_directories($$)
+{
+	my $filename = $_[0];
+	my $depth = $_[1];
+	my $i;
+
+	if (!defined($depth) || ($depth < 1))
+	{
+		return $filename;
+	}
+	for ($i = 0; $i < $depth; $i++)
+	{
+		$filename =~ s/^[^\/]*\/+(.*)$/$1/;
+	}
+	return $filename;
+}
+
+
+#
+# read_diff(filename)
+#
+# Read diff output from FILENAME to memory. The diff file has to follow the
+# format generated by 'diff -u'. Returns a list of hash references:
+#
+#   (mapping, path mapping)
+#
+#   mapping:   filename -> reference to line hash
+#   line hash: line number in new file -> corresponding line number in old file
+#
+#   path mapping:  filename -> old filename
+#
+# Die in case of error.
+#
+
+sub read_diff($)
+{
+	my $diff_file = $_[0];	# Name of diff file
+	my %diff;		# Resulting mapping filename -> line hash
+	my %paths;		# Resulting mapping old path  -> new path
+	my $mapping;		# Reference to current line hash
+	my $line;		# Contents of current line
+	my $num_old;		# Current line number in old file
+	my $num_new;		# Current line number in new file
+	my $file_old;		# Name of old file in diff section
+	my $file_new;		# Name of new file in diff section
+	my $filename;		# Name of common filename of diff section
+	my $in_block = 0;	# Non-zero while we are inside a diff block
+	local *HANDLE;		# File handle for reading the diff file
+
+	info("Reading diff $diff_file\n");
+
+	# Check if file exists and is readable
+	stat($diff_file);
+	if (!(-r _))
+	{
+		die("ERROR: cannot read file $diff_file!\n");
+	}
+
+	# Check if this is really a plain file
+	if (!(-f _))
+	{
+		die("ERROR: not a plain file: $diff_file!\n");
+	}
+
+	# Check for .gz extension
+	if ($diff_file =~ /\.gz$/)
+	{
+		# Check for availability of GZIP tool
+		system_no_output(1, "gunzip", "-h")
+			and die("ERROR: gunzip command not available!\n");
+
+		# Check integrity of compressed file
+		system_no_output(1, "gunzip", "-t", $diff_file)
+			and die("ERROR: integrity check failed for ".
+				"compressed file $diff_file!\n");
+
+		# Open compressed file
+		open(HANDLE, "-|", "gunzip -c '$diff_file'")
+			or die("ERROR: cannot start gunzip to decompress ".
+			       "file $_[0]!\n");
+	}
+	else
+	{
+		# Open decompressed file
+		open(HANDLE, "<", $diff_file)
+			or die("ERROR: cannot read file $_[0]!\n");
+	}
+
+	# Parse diff file line by line
+	while (<HANDLE>)
+	{
+		chomp($_);
+		$line = $_;
+
+		foreach ($line)
+		{
+			# Filename of old file:
+			# --- <filename> <date>
+			/^--- (\S+)/ && do
+			{
+				$file_old = strip_directories($1, $strip);
+				last;
+			};
+			# Filename of new file:
+			# +++ <filename> <date>
+			/^\+\+\+ (\S+)/ && do
+			{
+				# Add last file to resulting hash
+				if ($filename)
+				{
+					my %new_hash;
+					$diff{$filename} = $mapping;
+					$mapping = \%new_hash;
+				}
+				$file_new = strip_directories($1, $strip);
+				$filename = $file_old;
+				$paths{$filename} = $file_new;
+				$num_old = 1;
+				$num_new = 1;
+				last;
+			};
+			# Start of diff block:
+			# @@ -old_start,old_num, +new_start,new_num @@
+			/^\@\@\s+-(\d+),(\d+)\s+\+(\d+),(\d+)\s+\@\@$/ && do
+			{
+			$in_block = 1;
+			while ($num_old < $1)
+			{
+				$mapping->{$num_new} = $num_old;
+				$num_old++;
+				$num_new++;
+			}
+			last;
+			};
+			# Unchanged line
+			# <line starts with blank>
+			/^ / && do
+			{
+				if ($in_block == 0)
+				{
+					last;
+				}
+				$mapping->{$num_new} = $num_old;
+				$num_old++;
+				$num_new++;
+				last;
+			};
+			# Line as seen in old file
+			# <line starts with '-'>
+			/^-/ && do
+			{
+				if ($in_block == 0)
+				{
+					last;
+				}
+				$num_old++;
+				last;
+			};
+			# Line as seen in new file
+			# <line starts with '+'>
+			/^\+/ && do
+			{
+				if ($in_block == 0)
+				{
+					last;
+				}
+				$num_new++;
+				last;
+			};
+			# Empty line
+			/^$/ && do
+			{
+				if ($in_block == 0)
+				{
+					last;
+				}
+				$mapping->{$num_new} = $num_old;
+				$num_old++;
+				$num_new++;
+				last;
+			};
+		}
+	}
+
+	close(HANDLE);
+
+	# Add final diff file section to resulting hash
+	if ($filename)
+	{
+		$diff{$filename} = $mapping;
+	}
+
+	if (!%diff)
+	{
+		die("ERROR: no valid diff data found in $diff_file!\n".
+		    "Make sure to use 'diff -u' when generating the diff ".
+		    "file.\n");
+	}
+	return (\%diff, \%paths);
+}
+
+
+#
+# apply_diff($count_data, $line_hash)
+#
+# Transform count data using a mapping of lines:
+#
+#   $count_data: reference to hash: line number -> data
+#   $line_hash:  reference to hash: line number new -> line number old
+#
+# Return a reference to transformed count data.
+#
+
+sub apply_diff($$)
+{
+	my $count_data = $_[0];	# Reference to data hash: line -> hash
+	my $line_hash = $_[1];	# Reference to line hash: new line -> old line
+	my %result;		# Resulting hash
+	my $last_new = 0;	# Last new line number found in line hash
+	my $last_old = 0;	# Last old line number found in line hash
+
+	# Iterate all new line numbers found in the diff
+	foreach (sort({$a <=> $b} keys(%{$line_hash})))
+	{
+		$last_new = $_;
+		$last_old = $line_hash->{$last_new};
+
+		# Is there data associated with the corresponding old line?
+		if (defined($count_data->{$line_hash->{$_}}))
+		{
+			# Copy data to new hash with a new line number
+			$result{$_} = $count_data->{$line_hash->{$_}};
+		}
+	}
+	# Transform all other lines which come after the last diff entry
+	foreach (sort({$a <=> $b} keys(%{$count_data})))
+	{
+		if ($_ <= $last_old)
+		{
+			# Skip lines which were covered by line hash
+			next;
+		}
+		# Copy data to new hash with an offset
+		$result{$_ + ($last_new - $last_old)} = $count_data->{$_};
+	}
+
+	return \%result;
+}
+
+
+#
+# apply_diff_to_brcount(brcount, linedata)
+#
+# Adjust line numbers of branch coverage data according to linedata.
+#
+
+sub apply_diff_to_brcount($$)
+{
+	my ($brcount, $linedata) = @_;
+	my $db;
+
+	# Convert brcount to db format
+	$db = brcount_to_db($brcount);
+	# Apply diff to db format
+	$db = apply_diff($db, $linedata);
+	# Convert db format back to brcount format
+	($brcount) = db_to_brcount($db);
+
+	return $brcount;
+}
+
+
+#
+# get_hash_max(hash_ref)
+#
+# Return the highest integer key from hash.
+#
+
+sub get_hash_max($)
+{
+	my ($hash) = @_;
+	my $max;
+
+	foreach (keys(%{$hash})) {
+		if (!defined($max)) {
+			$max = $_;
+		} elsif ($hash->{$_} > $max) {
+			$max = $_;
+		}
+	}
+	return $max;
+}
+
+sub get_hash_reverse($)
+{
+	my ($hash) = @_;
+	my %result;
+
+	foreach (keys(%{$hash})) {
+		$result{$hash->{$_}} = $_;
+	}
+
+	return \%result;
+}
+
+#
+# apply_diff_to_funcdata(funcdata, line_hash)
+#
+
+sub apply_diff_to_funcdata($$)
+{
+	my ($funcdata, $linedata) = @_;
+	my $last_new = get_hash_max($linedata);
+	my $last_old = $linedata->{$last_new};
+	my $func;
+	my %result;
+	my $line_diff = get_hash_reverse($linedata);
+
+	foreach $func (keys(%{$funcdata})) {
+		my $line = $funcdata->{$func};
+
+		if (defined($line_diff->{$line})) {
+			$result{$func} = $line_diff->{$line};
+		} elsif ($line > $last_old) {
+			$result{$func} = $line + $last_new - $last_old;
+		}
+	}
+
+	return \%result;
+}
+
+
+#
+# get_line_hash($filename, $diff_data, $path_data)
+#
+# Find line hash in DIFF_DATA which matches FILENAME. On success, return list
+# line hash. or undef in case of no match. Die if more than one line hashes in
+# DIFF_DATA match.
+#
+
+sub get_line_hash($$$)
+{
+	my $filename = $_[0];
+	my $diff_data = $_[1];
+	my $path_data = $_[2];
+	my $conversion;
+	my $old_path;
+	my $new_path;
+	my $diff_name;
+	my $common;
+	my $old_depth;
+	my $new_depth;
+
+	# Remove trailing slash from diff path
+	$diff_path =~ s/\/$//;
+	foreach (keys(%{$diff_data}))
+	{
+		my $sep = "";
+
+		$sep = '/' if (!/^\//);
+
+		# Try to match diff filename with filename
+		if ($filename =~ /^\Q$diff_path$sep$_\E$/)
+		{
+			if ($diff_name)
+			{
+				# Two files match, choose the more specific one
+				# (the one with more path components)
+				$old_depth = ($diff_name =~ tr/\///);
+				$new_depth = (tr/\///);
+				if ($old_depth == $new_depth)
+				{
+					die("ERROR: diff file contains ".
+					    "ambiguous entries for ".
+					    "$filename\n");
+				}
+				elsif ($new_depth > $old_depth)
+				{
+					$diff_name = $_;
+				}
+			}
+			else
+			{
+				$diff_name = $_;
+			}
+		};
+	}
+	if ($diff_name)
+	{
+		# Get converted path
+		if ($filename =~ /^(.*)$diff_name$/)
+		{
+			($common, $old_path, $new_path) =
+				get_common_filename($filename,
+					$1.$path_data->{$diff_name});
+		}
+		return ($diff_data->{$diff_name}, $old_path, $new_path);
+	}
+	else
+	{
+		return undef;
+	}
+}
+
+
+#
+# convert_paths(trace_data, path_conversion_data)
+#
+# Rename all paths in TRACE_DATA which show up in PATH_CONVERSION_DATA.
+#
+
+sub convert_paths($$)
+{
+	my $trace_data = $_[0];
+	my $path_conversion_data = $_[1];
+	my $filename;
+	my $new_path;
+
+	if (scalar(keys(%{$path_conversion_data})) == 0)
+	{
+		info("No path conversion data available.\n");
+		return;
+	}
+
+	# Expand path conversion list
+	foreach $filename (keys(%{$path_conversion_data}))
+	{
+		$new_path = $path_conversion_data->{$filename};
+		while (($filename =~ s/^(.*)\/[^\/]+$/$1/) &&
+		       ($new_path =~ s/^(.*)\/[^\/]+$/$1/) &&
+		       ($filename ne $new_path))
+		{
+			$path_conversion_data->{$filename} = $new_path;
+		}
+	}
+
+	# Adjust paths
+	FILENAME: foreach $filename (keys(%{$trace_data}))
+	{
+		# Find a path in our conversion table that matches, starting
+		# with the longest path
+		foreach (sort({length($b) <=> length($a)}
+			      keys(%{$path_conversion_data})))
+		{
+			# Is this path a prefix of our filename?
+			if (!($filename =~ /^$_(.*)$/))
+			{
+				next;
+			}
+			$new_path = $path_conversion_data->{$_}.$1;
+
+			# Make sure not to overwrite an existing entry under
+			# that path name
+			if ($trace_data->{$new_path})
+			{
+				# Need to combine entries
+				$trace_data->{$new_path} =
+					combine_info_entries(
+						$trace_data->{$filename},
+						$trace_data->{$new_path},
+						$filename);
+			}
+			else
+			{
+				# Simply rename entry
+				$trace_data->{$new_path} =
+					$trace_data->{$filename};
+			}
+			delete($trace_data->{$filename});
+			next FILENAME;
+		}
+		info("No conversion available for filename $filename\n");
+	}
+}
+
+#
+# sub adjust_fncdata(funcdata, testfncdata, sumfnccount)
+#
+# Remove function call count data from testfncdata and sumfnccount which
+# is no longer present in funcdata.
+#
+
+sub adjust_fncdata($$$)
+{
+	my ($funcdata, $testfncdata, $sumfnccount) = @_;
+	my $testname;
+	my $func;
+	my $f_found;
+	my $f_hit;
+
+	# Remove count data in testfncdata for functions which are no longer
+	# in funcdata
+	foreach $testname (keys(%{$testfncdata})) {
+		my $fnccount = $testfncdata->{$testname};
+
+		foreach $func (keys(%{$fnccount})) {
+			if (!defined($funcdata->{$func})) {
+				delete($fnccount->{$func});
+			}
+		}
+	}
+	# Remove count data in sumfnccount for functions which are no longer
+	# in funcdata
+	foreach $func (keys(%{$sumfnccount})) {
+		if (!defined($funcdata->{$func})) {
+			delete($sumfnccount->{$func});
+		}
+	}
+}
+
+#
+# get_func_found_and_hit(sumfnccount)
+#
+# Return (f_found, f_hit) for sumfnccount
+#
+
+sub get_func_found_and_hit($)
+{
+	my ($sumfnccount) = @_;
+	my $function;
+	my $f_found;
+	my $f_hit;
+
+	$f_found = scalar(keys(%{$sumfnccount}));
+	$f_hit = 0;
+	foreach $function (keys(%{$sumfnccount})) {
+		if ($sumfnccount->{$function} > 0) {
+			$f_hit++;
+		}
+	}
+	return ($f_found, $f_hit);
+}
+
+#
+# diff()
+#
+
+sub diff()
+{
+	my $trace_data = read_info_file($diff);
+	my $diff_data;
+	my $path_data;
+	my $old_path;
+	my $new_path;
+	my %path_conversion_data;
+	my $filename;
+	my $line_hash;
+	my $new_name;
+	my $entry;
+	my $testdata;
+	my $testname;
+	my $sumcount;
+	my $funcdata;
+	my $checkdata;
+	my $testfncdata;
+	my $sumfnccount;
+	my $testbrdata;
+	my $sumbrcount;
+	my $found;
+	my $hit;
+	my $f_found;
+	my $f_hit;
+	my $br_found;
+	my $br_hit;
+	my $converted = 0;
+	my $unchanged = 0;
+	my @result;
+	local *INFO_HANDLE;
+
+	($diff_data, $path_data) = read_diff($ARGV[0]);
+
+        foreach $filename (sort(keys(%{$trace_data})))
+        {
+		# Find a diff section corresponding to this file
+		($line_hash, $old_path, $new_path) =
+			get_line_hash($filename, $diff_data, $path_data);
+		if (!$line_hash)
+		{
+			# There's no diff section for this file
+			$unchanged++;
+			next;
+		}
+		$converted++;
+		if ($old_path && $new_path && ($old_path ne $new_path))
+		{
+			$path_conversion_data{$old_path} = $new_path;
+		}
+		# Check for deleted files
+		if (scalar(keys(%{$line_hash})) == 0)
+		{
+			info("Removing $filename\n");
+			delete($trace_data->{$filename});
+			next;
+		}
+		info("Converting $filename\n");
+		$entry = $trace_data->{$filename};
+		($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
+		 $sumfnccount, $testbrdata, $sumbrcount) =
+			get_info_entry($entry);
+		# Convert test data
+		foreach $testname (keys(%{$testdata}))
+		{
+			# Adjust line numbers of line coverage data
+			$testdata->{$testname} =
+				apply_diff($testdata->{$testname}, $line_hash);
+			# Adjust line numbers of branch coverage data
+			$testbrdata->{$testname} =
+				apply_diff_to_brcount($testbrdata->{$testname},
+						      $line_hash);
+			# Remove empty sets of test data
+			if (scalar(keys(%{$testdata->{$testname}})) == 0)
+			{
+				delete($testdata->{$testname});
+				delete($testfncdata->{$testname});
+				delete($testbrdata->{$testname});
+			}
+		}
+		# Rename test data to indicate conversion
+		foreach $testname (keys(%{$testdata}))
+		{
+			# Skip testnames which already contain an extension
+			if ($testname =~ /,[^,]+$/)
+			{
+				next;
+			}
+			# Check for name conflict
+			if (defined($testdata->{$testname.",diff"}))
+			{
+				# Add counts
+				($testdata->{$testname}) = add_counts(
+					$testdata->{$testname},
+					$testdata->{$testname.",diff"});
+				delete($testdata->{$testname.",diff"});
+				# Add function call counts
+				($testfncdata->{$testname}) = add_fnccount(
+					$testfncdata->{$testname},
+					$testfncdata->{$testname.",diff"});
+				delete($testfncdata->{$testname.",diff"});
+				# Add branch counts
+				combine_brcount(
+					$testbrdata->{$testname},
+					$testbrdata->{$testname.",diff"},
+					$BR_ADD, 1);
+				delete($testbrdata->{$testname.",diff"});
+			}
+			# Move test data to new testname
+			$testdata->{$testname.",diff"} = $testdata->{$testname};
+			delete($testdata->{$testname});
+			# Move function call count data to new testname
+			$testfncdata->{$testname.",diff"} =
+				$testfncdata->{$testname};
+			delete($testfncdata->{$testname});
+			# Move branch count data to new testname
+			$testbrdata->{$testname.",diff"} =
+				$testbrdata->{$testname};
+			delete($testbrdata->{$testname});
+		}
+		# Convert summary of test data
+		$sumcount = apply_diff($sumcount, $line_hash);
+		# Convert function data
+		$funcdata = apply_diff_to_funcdata($funcdata, $line_hash);
+		# Convert branch coverage data
+		$sumbrcount = apply_diff_to_brcount($sumbrcount, $line_hash);
+		# Update found/hit numbers
+		# Convert checksum data
+		$checkdata = apply_diff($checkdata, $line_hash);
+		# Convert function call count data
+		adjust_fncdata($funcdata, $testfncdata, $sumfnccount);
+		($f_found, $f_hit) = get_func_found_and_hit($sumfnccount);
+		($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
+		# Update found/hit numbers
+		$found = 0;
+		$hit = 0;
+		foreach (keys(%{$sumcount}))
+		{
+			$found++;
+			if ($sumcount->{$_} > 0)
+			{
+				$hit++;
+			}
+		}
+		if ($found > 0)
+		{
+			# Store converted entry
+			set_info_entry($entry, $testdata, $sumcount, $funcdata,
+				       $checkdata, $testfncdata, $sumfnccount,
+				       $testbrdata, $sumbrcount, $found, $hit,
+				       $f_found, $f_hit, $br_found, $br_hit);
+		}
+		else
+		{
+			# Remove empty data set
+			delete($trace_data->{$filename});
+		}
+        }
+
+	# Convert filenames as well if requested
+	if ($convert_filenames)
+	{
+		convert_paths($trace_data, \%path_conversion_data);
+	}
+
+	info("$converted entr".($converted != 1 ? "ies" : "y")." converted, ".
+	     "$unchanged entr".($unchanged != 1 ? "ies" : "y")." left ".
+	     "unchanged.\n");
+
+	# Write data
+	if (!$data_stdout)
+	{
+		info("Writing data to $output_filename\n");
+		open(INFO_HANDLE, ">", $output_filename)
+			or die("ERROR: cannot write to $output_filename!\n");
+		@result = write_info_file(*INFO_HANDLE, $trace_data);
+		close(*INFO_HANDLE);
+	}
+	else
+	{
+		@result = write_info_file(*STDOUT, $trace_data);
+	}
+
+	return @result;
+}
+
+#
+# summary()
+#
+
+sub summary()
+{
+	my $filename;
+	my $current;
+	my $total;
+	my $ln_total_found;
+	my $ln_total_hit;
+	my $fn_total_found;
+	my $fn_total_hit;
+	my $br_total_found;
+	my $br_total_hit;
+
+	# Read and combine trace files
+	foreach $filename (@opt_summary) {
+		$current = read_info_file($filename);
+		if (!defined($total)) {
+			$total = $current;
+		} else {
+			$total = combine_info_files($total, $current);
+		}
+	}
+	# Calculate coverage data
+	foreach $filename (keys(%{$total}))
+	{
+		my $entry = $total->{$filename};
+		my $ln_found;
+		my $ln_hit;
+		my $fn_found;
+		my $fn_hit;
+		my $br_found;
+		my $br_hit;
+
+		(undef, undef, undef, undef, undef, undef, undef, undef,
+			$ln_found, $ln_hit, $fn_found, $fn_hit, $br_found,
+			$br_hit) = get_info_entry($entry);
+
+		# Add to totals
+		$ln_total_found	+= $ln_found;
+		$ln_total_hit	+= $ln_hit;
+		$fn_total_found += $fn_found;
+		$fn_total_hit	+= $fn_hit;
+		$br_total_found += $br_found;
+		$br_total_hit	+= $br_hit;
+	}
+
+
+	return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
+		$br_total_found, $br_total_hit);
+}
+
+#
+# system_no_output(mode, parameters)
+#
+# Call an external program using PARAMETERS while suppressing depending on
+# the value of MODE:
+#
+#   MODE & 1: suppress STDOUT
+#   MODE & 2: suppress STDERR
+#
+# Return 0 on success, non-zero otherwise.
+#
+
+sub system_no_output($@)
+{
+	my $mode = shift;
+	my $result;
+	local *OLD_STDERR;
+	local *OLD_STDOUT;
+
+	# Save old stdout and stderr handles
+	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
+
+	# Redirect to /dev/null
+	($mode & 1) && open(STDOUT, ">", "/dev/null");
+	($mode & 2) && open(STDERR, ">", "/dev/null");
+ 
+	system(@_);
+	$result = $?;
+
+	# Close redirected handles
+	($mode & 1) && close(STDOUT);
+	($mode & 2) && close(STDERR);
+
+	# Restore old handles
+	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
+ 
+	return $result;
+}
+
+
+#
+# read_config(filename)
+#
+# Read configuration file FILENAME and return a reference to a hash containing
+# all valid key=value pairs found.
+#
+
+sub read_config($)
+{
+	my $filename = $_[0];
+	my %result;
+	my $key;
+	my $value;
+	local *HANDLE;
+
+	if (!open(HANDLE, "<", $filename))
+	{
+		warn("WARNING: cannot read configuration file $filename\n");
+		return undef;
+	}
+	while (<HANDLE>)
+	{
+		chomp;
+		# Skip comments
+		s/#.*//;
+		# Remove leading blanks
+		s/^\s+//;
+		# Remove trailing blanks
+		s/\s+$//;
+		next unless length;
+		($key, $value) = split(/\s*=\s*/, $_, 2);
+		if (defined($key) && defined($value))
+		{
+			$result{$key} = $value;
+		}
+		else
+		{
+			warn("WARNING: malformed statement in line $. ".
+			     "of configuration file $filename\n");
+		}
+	}
+	close(HANDLE);
+	return \%result;
+}
+
+
+#
+# apply_config(REF)
+#
+# REF is a reference to a hash containing the following mapping:
+#
+#   key_string => var_ref
+#
+# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
+#
+
+sub apply_config($)
+{
+	my $ref = $_[0];
+
+	foreach (keys(%{$ref}))
+	{
+		if (defined($opt_rc{$_})) {
+			${$ref->{$_}} = $opt_rc{$_};
+		} elsif (defined($config->{$_})) {
+			${$ref->{$_}} = $config->{$_};
+		}
+	}
+}
+
+sub warn_handler($)
+{
+	my ($msg) = @_;
+
+	warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+	my ($msg) = @_;
+
+	temp_cleanup();
+	die("$tool_name: $msg");
+}
+
+sub abort_handler($)
+{
+	temp_cleanup();
+	exit(1);
+}
+
+sub temp_cleanup()
+{
+	# Ensure temp directory is not in use by current process
+	chdir("/");
+
+	if (@temp_dirs) {
+		info("Removing temporary directories.\n");
+		foreach (@temp_dirs) {
+			rmtree($_);
+		}
+		@temp_dirs = ();
+	}
+}
+
+sub setup_gkv_sys()
+{
+	system_no_output(3, "mount", "-t", "debugfs", "nodev",
+			 "/sys/kernel/debug");
+}
+
+sub setup_gkv_proc()
+{
+	if (system_no_output(3, "modprobe", "gcov_proc")) {
+		system_no_output(3, "modprobe", "gcov_prof");
+	}
+}
+
+sub check_gkv_sys($)
+{
+	my ($dir) = @_;
+
+	if (-e "$dir/reset") {
+		return 1;
+	}
+	return 0;
+}
+
+sub check_gkv_proc($)
+{
+	my ($dir) = @_;
+
+	if (-e "$dir/vmlinux") {
+		return 1;
+	}
+	return 0;
+}
+
+sub setup_gkv()
+{
+	my $dir;
+	my $sys_dir = "/sys/kernel/debug/gcov";
+	my $proc_dir = "/proc/gcov";
+	my @todo;
+
+	if (!defined($gcov_dir)) {
+		info("Auto-detecting gcov kernel support.\n");
+		@todo = ( "cs", "cp", "ss", "cs", "sp", "cp" );
+	} elsif ($gcov_dir =~ /proc/) {
+		info("Checking gcov kernel support at $gcov_dir ".
+		     "(user-specified).\n");
+		@todo = ( "cp", "sp", "cp", "cs", "ss", "cs");
+	} else {
+		info("Checking gcov kernel support at $gcov_dir ".
+		     "(user-specified).\n");
+		@todo = ( "cs", "ss", "cs", "cp", "sp", "cp", );
+	}
+	foreach (@todo) {
+		if ($_ eq "cs") {
+			# Check /sys
+			$dir = defined($gcov_dir) ? $gcov_dir : $sys_dir;
+			if (check_gkv_sys($dir)) {
+				info("Found ".$GKV_NAME[$GKV_SYS]." gcov ".
+				     "kernel support at $dir\n");
+				return ($GKV_SYS, $dir);
+			}
+		} elsif ($_ eq "cp") {
+			# Check /proc
+			$dir = defined($gcov_dir) ? $gcov_dir : $proc_dir;
+			if (check_gkv_proc($dir)) {
+				info("Found ".$GKV_NAME[$GKV_PROC]." gcov ".
+				     "kernel support at $dir\n");
+				return ($GKV_PROC, $dir);
+			}
+		} elsif ($_ eq "ss") {
+			# Setup /sys
+			setup_gkv_sys();
+		} elsif ($_ eq "sp") {
+			# Setup /proc
+			setup_gkv_proc();
+		}
+	}
+	if (defined($gcov_dir)) {
+		die("ERROR: could not find gcov kernel data at $gcov_dir\n");
+	} else {
+		die("ERROR: no gcov kernel data found\n");
+	}
+}
+
+
+#
+# get_overall_line(found, hit, name_singular, name_plural)
+#
+# Return a string containing overall information for the specified
+# found/hit data.
+#
+
+sub get_overall_line($$$$)
+{
+	my ($found, $hit, $name_sn, $name_pl) = @_;
+	my $name;
+
+	return "no data found" if (!defined($found) || $found == 0);
+	$name = ($found == 1) ? $name_sn : $name_pl;
+
+	return rate($hit, $found, "% ($hit of $found $name)");
+}
+
+
+#
+# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
+#                    br_found, br_hit)
+#
+# Print overall coverage rates for the specified coverage types.
+#
+
+sub print_overall_rate($$$$$$$$$)
+{
+	my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
+	    $br_do, $br_found, $br_hit) = @_;
+
+	info("Summary coverage rate:\n");
+	info("  lines......: %s\n",
+	     get_overall_line($ln_found, $ln_hit, "line", "lines"))
+		if ($ln_do);
+	info("  functions..: %s\n",
+	     get_overall_line($fn_found, $fn_hit, "function", "functions"))
+		if ($fn_do);
+	info("  branches...: %s\n",
+	     get_overall_line($br_found, $br_hit, "branch", "branches"))
+		if ($br_do);
+}
+
+
+#
+# rate(hit, found[, suffix, precision, width])
+#
+# Return the coverage rate [0..100] for HIT and FOUND values. 0 is only
+# returned when HIT is 0. 100 is only returned when HIT equals FOUND.
+# PRECISION specifies the precision of the result. SUFFIX defines a
+# string that is appended to the result if FOUND is non-zero. Spaces
+# are added to the start of the resulting string until it is at least WIDTH
+# characters wide.
+#
+
+sub rate($$;$$$)
+{
+        my ($hit, $found, $suffix, $precision, $width) = @_;
+        my $rate; 
+
+	# Assign defaults if necessary
+        $precision	= 1	if (!defined($precision));
+	$suffix		= ""	if (!defined($suffix));
+	$width		= 0	if (!defined($width));
+        
+        return sprintf("%*s", $width, "-") if (!defined($found) || $found == 0);
+        $rate = sprintf("%.*f", $precision, $hit * 100 / $found);
+
+	# Adjust rates if necessary
+        if ($rate == 0 && $hit > 0) {
+		$rate = sprintf("%.*f", $precision, 1 / 10 ** $precision);
+        } elsif ($rate == 100 && $hit != $found) {
+		$rate = sprintf("%.*f", $precision, 100 - 1 / 10 ** $precision);
+	}
+
+	return sprintf("%*s", $width, $rate.$suffix);
+}
diff --git a/externals/lcov/bin/updateversion.pl b/externals/lcov/bin/updateversion.pl
new file mode 100755
index 0000000000000000000000000000000000000000..19db81ecd3e3228e0f5115dada99755eae2f611d
--- /dev/null
+++ b/externals/lcov/bin/updateversion.pl
@@ -0,0 +1,194 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use File::Basename;
+
+sub update_man_page($);
+sub update_bin_tool($);
+sub update_txt_file($);
+sub update_spec_file($);
+sub write_version_file($);
+sub get_file_info($);
+
+our $directory = $ARGV[0];
+our $version = $ARGV[1];
+our $release = $ARGV[2];
+our $full = $ARGV[3];
+
+our @man_pages = ("man/gendesc.1",  "man/genhtml.1",  "man/geninfo.1",
+		  "man/genpng.1", "man/lcov.1", "man/lcovrc.5");
+our @bin_tools = ("bin/gendesc", "bin/genhtml", "bin/geninfo",
+		  "bin/genpng", "bin/lcov");
+our @txt_files = ("README");
+our @spec_files = ("rpm/lcov.spec");
+
+if (!defined($directory) || !defined($version) || !defined($release)) {
+	die("Usage: $0 DIRECTORY|FILE VERSION RELEASE FULL_VERSION\n");
+}
+
+# Determine mode of operation
+if (-f $directory) {
+	my $file = $directory;
+	my $base = basename($file);
+
+	if (grep(/^$base$/, map({ basename($_) } @man_pages))) {
+		print("Updating man page $file\n");
+		update_man_page($file);
+	} elsif (grep(/^$base$/, map({ basename($_) } @bin_tools))) {
+		print("Updating bin tool $file\n");
+		update_bin_tool($file);
+	} elsif (grep(/^$base$/, map({ basename($_) } @txt_files))) {
+		print("Updating text file $file\n");
+		update_txt_file($file);
+	} elsif (grep(/^$base$/, map({ basename($_) } @spec_files))) {
+		print("Updating spec file $file\n");
+		update_spec_file($file);
+	} elsif ($base eq ".version") {
+		print("Updating version file $file\n");
+		write_version_file($file);
+	} else {
+		print("WARNING: Skipping unknown file $file\n");
+	}
+	print("Done.\n");
+	exit(0);
+}
+
+foreach (@man_pages) {
+	print("Updating man page $_\n");
+	update_man_page($directory."/".$_);
+}
+foreach (@bin_tools) {
+	print("Updating bin tool $_\n");
+	update_bin_tool($directory."/".$_);
+}
+foreach (@txt_files) {
+	print("Updating text file $_\n");
+	update_txt_file($directory."/".$_);
+}
+foreach (@spec_files) {
+	print("Updating spec file $_\n");
+	update_spec_file($directory."/".$_);
+}
+print("Updating version file $directory/.version\n");
+write_version_file("$directory/.version");
+print("Done.\n");
+
+sub get_file_info($)
+{
+	my ($filename) = @_;
+	my ($sec, $min, $hour, $year, $month, $day);
+	my @stat;
+	my $gittime;
+
+	return (0, 0, 0) if (!-e $filename);
+	@stat = stat($filename);
+	($sec, $min, $hour, $day, $month, $year) = gmtime($stat[9]);
+	$year += 1900;
+	$month += 1;
+
+	return (sprintf("%04d-%02d-%02d", $year, $month, $day),
+		sprintf("%04d%02d%02d%02d%02d.%02d", $year, $month, $day,
+			$hour, $min, $sec),
+		sprintf("%o", $stat[2] & 07777));
+}
+
+sub update_man_page($)
+{
+	my ($filename) = @_;
+	my @date = get_file_info($filename);
+	my $date_string = $date[0];
+	local *IN;
+	local *OUT;
+
+	$date_string =~ s/-/\\-/g;
+	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
+	open(OUT, ">$filename.new") ||
+		die("Error: cannot create $filename.new\n");
+	while (<IN>) {
+		s/\"LCOV\s+\d+\.\d+\"/\"LCOV $version\"/g;
+		s/\d\d\d\d\\\-\d\d\\\-\d\d/$date_string/g;
+		print(OUT $_);
+	}
+	close(OUT);
+	close(IN);
+	chmod(oct($date[2]), "$filename.new");
+	system("mv", "-f", "$filename.new", "$filename");
+	system("touch", "$filename", "-t", $date[1]);
+}
+
+sub update_bin_tool($)
+{
+	my ($filename) = @_;
+	my @date = get_file_info($filename);
+	local *IN;
+	local *OUT;
+
+	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
+	open(OUT, ">$filename.new") ||
+		die("Error: cannot create $filename.new\n");
+	while (<IN>) {
+		s/^(our\s+\$lcov_version\s*=).*$/$1 "LCOV version $full";/g;
+		print(OUT $_);
+	}
+	close(OUT);
+	close(IN);
+	chmod(oct($date[2]), "$filename.new");
+	system("mv", "-f", "$filename.new", "$filename");
+	system("touch", "$filename", "-t", $date[1]);
+}
+
+sub update_txt_file($)
+{
+	my ($filename) = @_;
+	my @date = get_file_info($filename);
+	local *IN;
+	local *OUT;
+
+	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
+	open(OUT, ">$filename.new") ||
+		die("Error: cannot create $filename.new\n");
+	while (<IN>) {
+		s/(Last\s+changes:\s+)\d\d\d\d-\d\d-\d\d/$1$date[0]/g;
+		print(OUT $_);
+	}
+	close(OUT);
+	close(IN);
+	chmod(oct($date[2]), "$filename.new");
+	system("mv", "-f", "$filename.new", "$filename");
+	system("touch", "$filename", "-t", $date[1]);
+}
+
+sub update_spec_file($)
+{
+	my ($filename) = @_;
+	my @date = get_file_info($filename);
+	local *IN;
+	local *OUT;
+
+	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
+	open(OUT, ">$filename.new") ||
+		die("Error: cannot create $filename.new\n");
+	while (<IN>) {
+		s/^(Version:\s*)\d+\.\d+.*$/$1$version/;
+		s/^(Release:\s*).*$/$1$release/;
+		print(OUT $_);
+	}
+	close(OUT);
+	close(IN);
+	system("mv", "-f", "$filename.new", "$filename");
+	system("touch", "$filename", "-t", $date[1]);
+}
+
+sub write_version_file($)
+{
+	my ($filename) = @_;
+	my $fd;
+
+	open($fd, ">", $filename) or die("Error: cannot write $filename: $!\n");
+	print($fd "VERSION=$version\n");
+	print($fd "RELEASE=$release\n");
+	print($fd "FULL=$full\n");
+	close($fd);
+}
diff --git a/externals/lcov/example/Makefile b/externals/lcov/example/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2f698a1b32f3186a9e7d093742141b9a478f39f9
--- /dev/null
+++ b/externals/lcov/example/Makefile
@@ -0,0 +1,98 @@
+#
+# Makefile for the LCOV example program.
+#
+# Make targets:
+#   - example: compile the example program
+#   - output:  run test cases on example program and create HTML output
+#   - clean:   clean up directory
+#
+
+CC      := gcc
+CFLAGS  := -Wall -I. -fprofile-arcs -ftest-coverage
+
+LCOV    := ../bin/lcov
+GENHTML := ../bin/genhtml
+GENDESC := ../bin/gendesc
+GENPNG  := ../bin/genpng
+
+# Depending on the presence of the GD.pm perl module, we can use the
+# special option '--frames' for genhtml
+USE_GENPNG := $(shell $(GENPNG) --help >/dev/null 2>/dev/null; echo $$?)
+
+ifeq ($(USE_GENPNG),0)
+  FRAMES := --frames
+else
+  FRAMES :=
+endif
+
+.PHONY: clean output test_noargs test_2_to_2000 test_overflow
+
+all: output
+
+example: example.o iterate.o gauss.o
+	$(CC) example.o iterate.o gauss.o -o example -lgcov
+
+example.o: example.c iterate.h gauss.h
+	$(CC) $(CFLAGS) -c example.c -o example.o
+
+iterate.o: methods/iterate.c iterate.h
+	$(CC) $(CFLAGS) -c methods/iterate.c -o iterate.o
+
+gauss.o: methods/gauss.c gauss.h
+	$(CC) $(CFLAGS) -c methods/gauss.c -o gauss.o
+
+output: example descriptions test_noargs test_2_to_2000 test_overflow
+	@echo
+	@echo '*'
+	@echo '* Generating HTML output'
+	@echo '*'
+	@echo
+	$(GENHTML) trace_noargs.info trace_args.info trace_overflow.info \
+		   --output-directory output --title "Basic example" \
+		   --show-details --description-file descriptions $(FRAMES) \
+		   --legend
+	@echo
+	@echo '*'
+	@echo '* See '`pwd`/output/index.html
+	@echo '*'
+	@echo
+
+descriptions: descriptions.txt
+	$(GENDESC) descriptions.txt -o descriptions
+
+all_tests: example test_noargs test_2_to_2000 test_overflow
+
+test_noargs:
+	@echo
+	@echo '*'
+	@echo '* Test case 1: running ./example without parameters'
+	@echo '*'
+	@echo
+	$(LCOV) --zerocounters --directory .
+	./example
+	$(LCOV) --capture --directory . --output-file trace_noargs.info --test-name test_noargs --no-external
+
+test_2_to_2000:
+	@echo
+	@echo '*'
+	@echo '* Test case 2: running ./example 2 2000'
+	@echo '*'
+	@echo
+	$(LCOV) --zerocounters --directory .
+	./example 2 2000
+	$(LCOV) --capture --directory . --output-file trace_args.info --test-name test_2_to_2000 --no-external
+
+test_overflow:
+	@echo
+	@echo '*'
+	@echo '* Test case 3: running ./example 0 100000 (causes an overflow)'
+	@echo '*'
+	@echo
+	$(LCOV) --zerocounters --directory .
+	./example 0 100000 || true
+	$(LCOV) --capture --directory . --output-file trace_overflow.info --test-name "test_overflow" --no-external
+
+clean:
+	rm -rf *.o *.bb *.bbg *.da *.gcno *.gcda *.info output example \
+	descriptions
+
diff --git a/externals/lcov/example/README b/externals/lcov/example/README
new file mode 100644
index 0000000000000000000000000000000000000000..cf6cf2e4c688d32220293484bcfaf9794f16abf8
--- /dev/null
+++ b/externals/lcov/example/README
@@ -0,0 +1,6 @@
+
+To get an example of how the LCOV generated HTML output looks like,
+type 'make output' and point a web browser to the resulting file
+
+  output/index.html
+
diff --git a/externals/lcov/example/descriptions.txt b/externals/lcov/example/descriptions.txt
new file mode 100644
index 0000000000000000000000000000000000000000..47e6021310d3ed1bb55d2a1bf239ff9dab1d2b82
--- /dev/null
+++ b/externals/lcov/example/descriptions.txt
@@ -0,0 +1,10 @@
+test_noargs
+	Example program is called without arguments so that default range
+	[0..9] is used.
+
+test_2_to_2000
+	Example program is called with "2" and "2000" as arguments.
+
+test_overflow
+	Example program is called with "0" and "100000" as arguments. The
+	resulting sum is too large to be stored as an int variable.
diff --git a/externals/lcov/example/example.c b/externals/lcov/example/example.c
new file mode 100644
index 0000000000000000000000000000000000000000..f9049aa64bafad3aad81910c355c625742290008
--- /dev/null
+++ b/externals/lcov/example/example.c
@@ -0,0 +1,60 @@
+/*
+ *  example.c
+ * 
+ *  Calculate the sum of a given range of integer numbers. The range is
+ *  specified by providing two integer numbers as command line argument.
+ *  If no arguments are specified, assume the predefined range [0..9].
+ *  Abort with an error message if the resulting number is too big to be
+ *  stored as int variable.
+ *
+ *  This program example is similar to the one found in the GCOV documentation.
+ *  It is used to demonstrate the HTML output generated by LCOV.
+ *
+ *  The program is split into 3 modules to better demonstrate the 'directory
+ *  overview' function. There are also a lot of bloated comments inserted to
+ *  artificially increase the source code size so that the 'source code
+ *  overview' function makes at least a minimum of sense.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "iterate.h"
+#include "gauss.h"
+
+static int start = 0;
+static int end = 9;
+
+
+int main (int argc, char* argv[])
+{
+	int total1, total2;
+
+	/* Accept a pair of numbers as command line arguments. */
+
+	if (argc == 3)
+	{
+		start	= atoi(argv[1]);
+		end	= atoi(argv[2]);
+	}
+
+
+	/* Use both methods to calculate the result. */
+
+	total1 = iterate_get_sum (start, end);
+	total2 = gauss_get_sum (start, end);
+
+
+	/* Make sure both results are the same. */
+
+	if (total1 != total2)
+	{
+		printf ("Failure (%d != %d)!\n", total1, total2);
+	}
+	else
+	{
+		printf ("Success, sum[%d..%d] = %d\n", start, end, total1);
+	}
+
+	return 0;
+}
diff --git a/externals/lcov/example/gauss.h b/externals/lcov/example/gauss.h
new file mode 100644
index 0000000000000000000000000000000000000000..302a4a980382ed38909900cc941e91069a30b96e
--- /dev/null
+++ b/externals/lcov/example/gauss.h
@@ -0,0 +1,6 @@
+#ifndef GAUSS_H
+#define GAUSS_H GAUSS_h
+
+extern int gauss_get_sum (int min, int max);
+
+#endif /* GAUSS_H */
diff --git a/externals/lcov/example/iterate.h b/externals/lcov/example/iterate.h
new file mode 100644
index 0000000000000000000000000000000000000000..471327951cf470e9e5b1e7286583c15124b28c3e
--- /dev/null
+++ b/externals/lcov/example/iterate.h
@@ -0,0 +1,6 @@
+#ifndef ITERATE_H
+#define ITERATE_H ITERATE_H
+
+extern int iterate_get_sum (int min, int max);
+
+#endif /* ITERATE_H */
diff --git a/externals/lcov/example/methods/gauss.c b/externals/lcov/example/methods/gauss.c
new file mode 100644
index 0000000000000000000000000000000000000000..9da3ce50835b1f32141b1d4ba321abd053ac0aac
--- /dev/null
+++ b/externals/lcov/example/methods/gauss.c
@@ -0,0 +1,48 @@
+/*
+ *  methods/gauss.c
+ *
+ *  Calculate the sum of a given range of integer numbers.
+ *
+ *  Somewhat of a more subtle way of calculation - and it even has a story
+ *  behind it:
+ *
+ *  Supposedly during math classes in elementary school, the teacher of
+ *  young mathematician Gauss gave the class an assignment to calculate the
+ *  sum of all natural numbers between 1 and 100, hoping that this task would
+ *  keep the kids occupied for some time. The story goes that Gauss had the
+ *  result ready after only a few minutes. What he had written on his black
+ *  board was something like this:
+ *
+ *    1 + 100 = 101
+ *    2 + 99  = 101
+ *    3 + 98  = 101
+ *    .
+ *    .
+ *    100 + 1 = 101
+ *
+ *    s = (1/2) * 100 * 101 = 5050
+ *
+ *  A more general form of this formula would be
+ *  
+ *    s = (1/2) * (max + min) * (max - min + 1)
+ *
+ *  which is used in the piece of code below to implement the requested
+ *  function in constant time, i.e. without dependencies on the size of the
+ *  input parameters.
+ *
+ */
+
+#include "gauss.h"
+
+
+int gauss_get_sum (int min, int max)
+{
+	/* This algorithm doesn't work well with invalid range specifications
+	   so we're intercepting them here. */
+	if (max < min)
+	{
+		return 0;
+	}
+
+	return (int) ((max + min) * (double) (max - min + 1) / 2);
+}
diff --git a/externals/lcov/example/methods/iterate.c b/externals/lcov/example/methods/iterate.c
new file mode 100644
index 0000000000000000000000000000000000000000..023d1801c9364f71c994e8c0dbe04b93f3992f34
--- /dev/null
+++ b/externals/lcov/example/methods/iterate.c
@@ -0,0 +1,45 @@
+/*
+ *  methods/iterate.c
+ *  
+ *  Calculate the sum of a given range of integer numbers.
+ *
+ *  This particular method of implementation works by way of brute force,
+ *  i.e. it iterates over the entire range while adding the numbers to finally
+ *  get the total sum. As a positive side effect, we're able to easily detect
+ *  overflows, i.e. situations in which the sum would exceed the capacity
+ *  of an integer variable.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "iterate.h"
+
+
+int iterate_get_sum (int min, int max)
+{
+	int i, total;
+
+	total = 0;
+
+	/* This is where we loop over each number in the range, including
+	   both the minimum and the maximum number. */
+
+	for (i = min; i <= max; i++)
+	{
+		/* We can detect an overflow by checking whether the new
+		   sum would become negative. */
+
+		if (total + i < total)
+		{
+			printf ("Error: sum too large!\n");
+			exit (1);
+		}
+
+		/* Everything seems to fit into an int, so continue adding. */
+
+		total += i;
+	}
+
+	return total;
+}
diff --git a/externals/lcov/lcovrc b/externals/lcov/lcovrc
new file mode 100644
index 0000000000000000000000000000000000000000..40f364f17aa6497f4ccd8af98145367f4b8341ae
--- /dev/null
+++ b/externals/lcov/lcovrc
@@ -0,0 +1,169 @@
+#
+# /etc/lcovrc - system-wide defaults for LCOV
+#
+# To change settings for a single user, place a customized copy of this file
+# at location ~/.lcovrc
+#
+
+# Specify an external style sheet file (same as --css-file option of genhtml)
+#genhtml_css_file = gcov.css
+
+# Specify coverage rate limits (in %) for classifying file entries
+# HI:   hi_limit <= rate <= 100         graph color: green
+# MED: med_limit <= rate <  hi_limit    graph color: orange
+# LO:         0  <= rate <  med_limit   graph color: red
+genhtml_hi_limit = 90
+genhtml_med_limit = 75
+
+# Width of line coverage field in source code view
+genhtml_line_field_width = 12
+
+# Width of branch coverage field in source code view
+genhtml_branch_field_width = 16
+
+# Width of overview image (used by --frames option of genhtml)
+genhtml_overview_width = 80
+
+# Resolution of overview navigation: this number specifies the maximum
+# difference in lines between the position a user selected from the overview
+# and the position the source code window is scrolled to (used by --frames
+# option of genhtml)
+genhtml_nav_resolution = 4
+
+# Clicking a line in the overview image should show the source code view at
+# a position a bit further up so that the requested line is not the first
+# line in the window. This number specifies that offset in lines (used by
+# --frames option of genhtml)
+genhtml_nav_offset = 10
+
+# Do not remove unused test descriptions if non-zero (same as
+# --keep-descriptions option of genhtml)
+genhtml_keep_descriptions = 0
+
+# Do not remove prefix from directory names if non-zero (same as --no-prefix
+# option of genhtml)
+genhtml_no_prefix = 0
+
+# Do not create source code view if non-zero (same as --no-source option of
+# genhtml)
+genhtml_no_source = 0
+
+# Replace tabs with number of spaces in source view (same as --num-spaces
+# option of genhtml)
+genhtml_num_spaces = 8
+
+# Highlight lines with converted-only data if non-zero (same as --highlight
+# option of genhtml)
+genhtml_highlight = 0
+
+# Include color legend in HTML output if non-zero (same as --legend option of
+# genhtml)
+genhtml_legend = 0
+
+# Use FILE as HTML prolog for generated pages (same as --html-prolog option of
+# genhtml)
+#genhtml_html_prolog = FILE
+
+# Use FILE as HTML epilog for generated pages (same as --html-epilog option of
+# genhtml)
+#genhtml_html_epilog = FILE
+
+# Use custom filename extension for pages (same as --html-extension option of
+# genhtml)
+#genhtml_html_extension = html
+
+# Compress all generated html files with gzip.
+#genhtml_html_gzip = 1
+
+# Include sorted overview pages (can be disabled by the --no-sort option of
+# genhtml)
+genhtml_sort = 1
+
+# Include function coverage data display (can be disabled by the
+# --no-func-coverage option of genhtml)
+#genhtml_function_coverage = 1
+
+# Include branch coverage data display (can be disabled by the
+# --no-branch-coverage option of genhtml)
+#genhtml_branch_coverage = 1
+
+# Specify the character set of all generated HTML pages
+genhtml_charset=UTF-8
+
+# Allow HTML markup in test case description text if non-zero
+genhtml_desc_html=0
+
+# Specify the precision for coverage rates
+#genhtml_precision=1
+
+# Show missed counts instead of hit counts
+#genhtml_missed=1
+
+# Demangle C++ symbols
+#genhtml_demangle_cpp=1
+
+# Location of the gcov tool (same as --gcov-info option of geninfo)
+#geninfo_gcov_tool = gcov
+
+# Adjust test names to include operating system information if non-zero
+#geninfo_adjust_testname = 0
+
+# Calculate checksum for each source code line if non-zero (same as --checksum
+# option of geninfo if non-zero, same as --no-checksum if zero)
+#geninfo_checksum = 1
+
+# Specify whether to capture coverage data for external source files (can
+# be overridden by the --external and --no-external options of geninfo/lcov)
+#geninfo_external = 1
+
+# Enable libtool compatibility mode if non-zero (same as --compat-libtool option
+# of geninfo if non-zero, same as --no-compat-libtool if zero)
+#geninfo_compat_libtool = 0
+
+# Use gcov's --all-blocks option if non-zero
+#geninfo_gcov_all_blocks = 1
+
+# Specify compatiblity modes (same as --compat option of geninfo).
+#geninfo_compat = libtool=on, hammer=auto, split_crc=auto
+
+# Adjust path to source files by removing or changing path components that
+# match the specified pattern (Perl regular expression format)
+#geninfo_adjust_src_path = /tmp/build => /usr/src
+
+# Specify if geninfo should try to automatically determine the base-directory
+# when collecting coverage data.
+geninfo_auto_base = 1
+
+# Directory containing gcov kernel files
+# lcov_gcov_dir = /proc/gcov
+
+# Location of the insmod tool
+lcov_insmod_tool = /sbin/insmod
+
+# Location of the modprobe tool
+lcov_modprobe_tool = /sbin/modprobe
+
+# Location of the rmmod tool
+lcov_rmmod_tool = /sbin/rmmod
+
+# Location for temporary directories
+lcov_tmp_dir = /tmp
+
+# Show full paths during list operation if non-zero (same as --list-full-path
+# option of lcov)
+lcov_list_full_path = 0
+
+# Specify the maximum width for list output. This value is ignored when
+# lcov_list_full_path is non-zero.
+lcov_list_width = 80
+
+# Specify the maximum percentage of file names which may be truncated when
+# choosing a directory prefix in list output. This value is ignored when
+# lcov_list_full_path is non-zero.
+lcov_list_truncate_max = 20
+
+# Specify if function coverage data should be collected and processed.
+lcov_function_coverage = 1
+
+# Specify if branch coverage data should be collected and processed.
+lcov_branch_coverage = 0
diff --git a/externals/lcov/man/gendesc.1 b/externals/lcov/man/gendesc.1
new file mode 100644
index 0000000000000000000000000000000000000000..9c9a7084db2f39c8245a19c2a08db3e610acf5b8
--- /dev/null
+++ b/externals/lcov/man/gendesc.1
@@ -0,0 +1,78 @@
+.TH gendesc 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.SH NAME
+gendesc \- Generate a test case description file
+.SH SYNOPSIS
+.B gendesc
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-version ]
+.RS 8
+.br
+.RB [ \-o | \-\-output\-filename
+.IR filename ]
+.br
+.I inputfile
+.SH DESCRIPTION
+Convert plain text test case descriptions into a format as understood by
+.BR genhtml .
+.I inputfile
+needs to observe the following format:
+
+For each test case:
+.IP "     \-"
+one line containing the test case name beginning at the start of the line
+.RE
+.IP "     \-"
+one or more lines containing the test case description indented with at
+least one whitespace character (tab or space)
+.RE
+
+.B Example input file:
+
+test01
+.RS
+An example test case description.
+.br
+Description continued
+.RE
+
+test42
+.RS
+Supposedly the answer to most of your questions
+.RE
+
+Note: valid test names can consist of letters, decimal digits and the
+underscore character ('_').
+.SH OPTIONS
+.B \-h
+.br
+.B \-\-help
+.RS
+Print a short help text, then exit.
+.RE
+
+.B \-v
+.br
+.B \-\-version
+.RS
+Print version number, then exit.
+.RE
+
+
+.BI "\-o " filename
+.br
+.BI "\-\-output\-filename " filename
+.RS
+Write description data to
+.IR filename .
+
+By default, output is written to STDOUT.
+.RE
+.SH AUTHOR
+Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+
+.SH SEE ALSO
+.BR lcov (1),
+.BR genhtml (1),
+.BR geninfo (1),
+.BR genpng (1),
+.BR gcov (1)
diff --git a/externals/lcov/man/genhtml.1 b/externals/lcov/man/genhtml.1
new file mode 100644
index 0000000000000000000000000000000000000000..949bd4c574b977f1824150751763e2c81a45bb95
--- /dev/null
+++ b/externals/lcov/man/genhtml.1
@@ -0,0 +1,600 @@
+.TH genhtml 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.SH NAME
+genhtml \- Generate HTML view from LCOV coverage data files
+.SH SYNOPSIS
+.B genhtml
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-version ]
+.RS 8
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-s | \-\-show\-details ]
+.RB [ \-f | \-\-frames ]
+.br
+.RB [ \-b | \-\-baseline\-file  ]
+.IR baseline\-file
+.br
+.RB [ \-o | \-\-output\-directory
+.IR output\-directory ]
+.br
+.RB [ \-t | \-\-title
+.IR title ]
+.br
+.RB [ \-d | \-\-description\-file
+.IR description\-file ]
+.br
+.RB [ \-k | \-\-keep\-descriptions ]
+.RB [ \-c | \-\-css\-file
+.IR css\-file ]
+.br
+.RB [ \-p | \-\-prefix
+.IR prefix ]
+.RB [ \-\-no\-prefix ]
+.br
+.RB [ \-\-no\-source ]
+.RB [ \-\-num\-spaces
+.IR num ]
+.RB [ \-\-highlight ]
+.br
+.RB [ \-\-legend ]
+.RB [ \-\-html\-prolog
+.IR prolog\-file ]
+.br
+.RB [ \-\-html\-epilog
+.IR epilog\-file ]
+.RB [ \-\-html\-extension
+.IR extension ]
+.br
+.RB [ \-\-html\-gzip ]
+.RB [ \-\-sort ]
+.RB [ \-\-no\-sort ]
+.br
+.RB [ \-\-function\-coverage ]
+.RB [ \-\-no\-function\-coverage ]
+.br
+.RB [ \-\-branch\-coverage ]
+.RB [ \-\-no\-branch\-coverage ]
+.br
+.RB [ \-\-demangle\-cpp ]
+.RB [ \-\-ignore\-errors
+.IR errors  ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RB [ \-\-precision
+.RB [ \-\-missed ]
+.br
+.IR tracefile(s)
+.RE
+.SH DESCRIPTION
+Create an HTML view of coverage data found in
+.IR tracefile .
+Note that
+.I tracefile
+may also be a list of filenames.
+
+HTML output files are created in the current working directory unless the
+\-\-output\-directory option is used. If 
+.I tracefile
+ends with ".gz", it is assumed to be GZIP\-compressed and the gunzip tool
+will be used to decompress it transparently.
+
+Note that all source code files have to be present and readable at the
+exact file system location they were compiled.
+
+Use option
+.I \--css\-file
+to modify layout and colors of the generated HTML output. Files are
+marked in different colors depending on the associated coverage rate. By
+default, the coverage limits for low, medium and high coverage are set to
+0\-75%, 75\-90% and 90\-100% percent respectively. To change these
+values, use configuration file options
+.IR genhtml_hi_limit " and " genhtml_med_limit .
+
+Also note that when displaying percentages, 0% and 100% are only printed when
+the values are exactly 0% and 100% respectively. Other values which would
+conventionally be rounded to 0% or 100% are instead printed as nearest
+non-boundary value. This behavior is in accordance with that of the
+.BR gcov (1)
+tool.
+
+.SH OPTIONS
+.B \-h
+.br
+.B \-\-help
+.RS
+Print a short help text, then exit.
+
+.RE
+.B \-v
+.br
+.B \-\-version
+.RS
+Print version number, then exit.
+
+.RE
+.B \-q
+.br
+.B \-\-quiet
+.RS
+Do not print progress messages.
+
+Suppresses all informational progress output. When this switch is enabled,
+only error or warning messages are printed.
+
+.RE
+.B \-f
+.br
+.B \-\-frames
+.RS
+Use HTML frames for source code view.
+
+If enabled, a frameset is created for each source code file, providing
+an overview of the source code as a "clickable" image. Note that this
+option will slow down output creation noticeably because each source
+code character has to be inspected once. Note also that the GD.pm Perl
+module has to be installed for this option to work (it may be obtained
+from http://www.cpan.org).
+
+.RE
+.B \-s
+.br
+.B \-\-show\-details
+.RS
+Generate detailed directory view.
+
+When this option is enabled,
+.B genhtml
+generates two versions of each
+file view. One containing the standard information plus a link to a
+"detailed" version. The latter additionally contains information about
+which test case covered how many lines of each source file.
+
+.RE
+.BI "\-b " baseline\-file
+.br
+.BI "\-\-baseline\-file " baseline\-file
+.RS
+Use data in
+.I baseline\-file
+as coverage baseline.
+
+The tracefile specified by
+.I baseline\-file
+is read and all counts found in the original
+.I tracefile
+are decremented by the corresponding counts in 
+.I baseline\-file
+before creating any output.
+
+Note that when a count for a particular line in
+.I baseline\-file
+is greater than the count in the
+.IR tracefile ,
+the result is zero.
+
+.RE
+.BI "\-o " output\-directory
+.br
+.BI "\-\-output\-directory " output\-directory
+.RS
+Create files in 
+.I output\-directory.
+
+Use this option to tell 
+.B genhtml
+to write the resulting files to a directory other than
+the current one. If 
+.I output\-directory
+does not exist, it will be created.
+
+It is advisable to use this option since depending on the
+project size, a lot of files and subdirectories may be created.
+
+.RE
+.BI "\-t " title
+.br
+.BI "\-\-title " title
+.RS
+Display 
+.I title
+in header of all pages.
+
+.I title
+is written to the header portion of each generated HTML page to
+identify the context in which a particular output
+was created. By default this is the name of the tracefile.
+
+.RE
+.BI "\-d " description\-file
+.br
+.BI "\-\-description\-file " description\-file
+.RS
+Read test case descriptions from 
+.IR description\-file .
+
+All test case descriptions found in
+.I description\-file
+and referenced in the input data file are read and written to an extra page
+which is then incorporated into the HTML output.
+
+The file format of
+.IR "description\-file " is:
+
+for each test case:
+.RS
+TN:<testname>
+.br
+TD:<test description>
+
+.RE
+
+Valid test case names can consist of letters, numbers and the underscore
+character ('_').
+.RE
+.B \-k
+.br
+.B \-\-keep\-descriptions
+.RS
+Do not remove unused test descriptions.
+
+Keep descriptions found in the description file even if the coverage data
+indicates that the associated test case did not cover any lines of code.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_keep_descriptions .
+
+.RE
+.BI "\-c " css\-file
+.br
+.BI "\-\-css\-file " css\-file
+.RS
+Use external style sheet file
+.IR css\-file .
+
+Using this option, an extra .css file may be specified which will replace
+the default one. This may be helpful if the default colors make your eyes want
+to jump out of their sockets :)
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_css_file .
+
+.RE
+.BI "\-p " prefix
+.br
+.BI "\-\-prefix " prefix
+.RS
+Remove 
+.I prefix
+from all directory names.
+
+Because lists containing long filenames are difficult to read, there is a
+mechanism implemented that will automatically try to shorten all directory
+names on the overview page beginning with a common prefix. By default,
+this is done using an algorithm that tries to find the prefix which, when
+applied, will minimize the resulting sum of characters of all directory
+names.
+
+Use this option to specify the prefix to be removed by yourself.
+
+.RE
+.B \-\-no\-prefix
+.RS
+Do not remove prefix from directory names.
+
+This switch will completely disable the prefix mechanism described in the
+previous section.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_no_prefix .
+
+.RE
+.B \-\-no\-source
+.RS
+Do not create source code view.
+
+Use this switch if you don't want to get a source code view for each file.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_no_source .
+
+.RE
+.BI "\-\-num\-spaces " spaces
+.RS
+Replace tabs in source view with
+.I num
+spaces.
+
+Default value is 8.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_num_spaces .
+
+.RE
+.B \-\-highlight
+.RS
+Highlight lines with converted\-only coverage data.
+
+Use this option in conjunction with the \-\-diff option of
+.B lcov
+to highlight those lines which were only covered in data sets which were
+converted from previous source code versions.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_highlight .
+
+.RE
+.B \-\-legend
+.RS
+Include color legend in HTML output.
+
+Use this option to include a legend explaining the meaning of color coding
+in the resulting HTML output.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_legend .
+
+.RE
+.BI "\-\-html\-prolog " prolog\-file
+.RS
+Read customized HTML prolog from 
+.IR prolog\-file .
+
+Use this option to replace the default HTML prolog (the initial part of the
+HTML source code leading up to and including the <body> tag) with the contents
+of
+.IR prolog\-file .
+Within the prolog text, the following words will be replaced when a page is generated:
+
+.B "@pagetitle@"
+.br
+The title of the page.
+
+.B "@basedir@"
+.br
+A relative path leading to the base directory (e.g. for locating css\-files).
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_html_prolog .
+
+.RE
+.BI "\-\-html\-epilog " epilog\-file
+.RS
+Read customized HTML epilog from 
+.IR epilog\-file .
+
+Use this option to replace the default HTML epilog (the final part of the HTML
+source including </body>) with the contents of
+.IR epilog\-file .
+
+Within the epilog text, the following words will be replaced when a page is generated:
+
+.B "@basedir@"
+.br
+A relative path leading to the base directory (e.g. for locating css\-files).
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_html_epilog .
+
+.RE
+.BI "\-\-html\-extension " extension
+.RS
+Use customized filename extension for generated HTML pages.
+
+This option is useful in situations where different filename extensions
+are required to render the resulting pages correctly (e.g. php). Note that
+a '.' will be inserted between the filename and the extension specified by
+this option.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_html_extension .
+.RE
+
+.B \-\-html\-gzip
+.RS
+Compress all generated html files with gzip and add a .htaccess file specifying
+gzip\-encoding in the root output directory.
+
+Use this option if you want to save space on your webserver. Requires a
+webserver with .htaccess support and a browser with support for gzip
+compressed html.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_html_gzip .
+
+.RE
+.B \-\-sort
+.br
+.B \-\-no\-sort
+.RS
+Specify whether to include sorted views of file and directory overviews.
+
+Use \-\-sort to include sorted views or \-\-no\-sort to not include them.
+Sorted views are
+.B enabled
+by default.
+
+When sorted views are enabled, each overview page will contain links to
+views of that page sorted by coverage rate.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_sort .
+
+.RE
+.B \-\-function\-coverage
+.br
+.B \-\-no\-function\-coverage
+.RS
+Specify whether to display function coverage summaries in HTML output.
+
+Use \-\-function\-coverage to enable function coverage summaries or
+\-\-no\-function\-coverage to disable it. Function coverage summaries are
+.B enabled
+by default
+
+When function coverage summaries are enabled, each overview page will contain
+the number of functions found and hit per file or directory, together with
+the resulting coverage rate. In addition, each source code view will contain
+a link to a page which lists all functions found in that file plus the
+respective call count for those functions.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_function_coverage .
+
+.RE
+.B \-\-branch\-coverage
+.br
+.B \-\-no\-branch\-coverage
+.RS
+Specify whether to display branch coverage data in HTML output.
+
+Use \-\-branch\-coverage to enable branch coverage display or
+\-\-no\-branch\-coverage to disable it. Branch coverage data display is
+.B enabled
+by default
+
+When branch coverage display is enabled, each overview page will contain
+the number of branches found and hit per file or directory, together with
+the resulting coverage rate. In addition, each source code view will contain
+an extra column which lists all branches of a line with indications of
+whether the branch was taken or not. Branches are shown in the following format:
+
+ ' + ': Branch was taken at least once
+.br
+ ' - ': Branch was not taken
+.br
+ ' # ': The basic block containing the branch was never executed
+.br
+
+Note that it might not always be possible to relate branches to the
+corresponding source code statements: during compilation, GCC might shuffle
+branches around or eliminate some of them to generate better code.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_branch_coverage .
+
+.RE
+.B \-\-demangle\-cpp
+.RS
+Specify whether to demangle C++ function names.
+
+Use this option if you want to convert C++ internal function names to
+human readable format for display on the HTML function overview page.
+This option requires that the c++filt tool is installed (see
+.BR c++filt (1)).
+
+.RE
+.B \-\-ignore\-errors
+.I errors
+.br
+.RS
+Specify a list of errors after which to continue processing.
+
+Use this option to specify a list of one or more classes of errors after which
+geninfo should continue processing instead of aborting.
+
+.I errors
+can be a comma\-separated list of the following keywords:
+
+.B source:
+the source code file for a data set could not be found.
+.RE
+
+.B \-\-config\-file
+.I config\-file
+.br
+.RS
+Specify a configuration file to use.
+
+When this option is specified, neither the system\-wide configuration file
+/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
+
+This option may be useful when there is a need to run several
+instances of
+.B genhtml
+with different configuration file options in parallel.
+.RE
+
+.B \-\-rc
+.IR keyword = value
+.br
+.RS
+Override a configuration directive.
+
+Use this option to specify a
+.IR keyword = value
+statement which overrides the corresponding configuration statement in
+the lcovrc configuration file. You can specify this option more than once
+to override multiple configuration statements.
+See
+.BR lcovrc (5)
+for a list of available keywords and their meaning.
+.RE
+
+.BI "\-\-precision " num
+.RS
+Show coverage rates with
+.I num
+number of digits after the decimal-point.
+
+Default value is 1.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_precision .
+.RE
+
+.B \-\-missed
+.RS
+Show counts of missed lines, functions, or branches
+
+Use this option to change overview pages to show the count of lines, functions,
+or branches that were not hit. These counts are represented by negative numbers.
+
+When specified together with \-\-sort, file and directory views will be sorted
+by missed counts.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_missed .
+.RE
+
+.SH FILES
+
+.I /etc/lcovrc
+.RS
+The system\-wide configuration file.
+.RE
+
+.I ~/.lcovrc
+.RS
+The per\-user configuration file.
+.RE
+
+.SH AUTHOR
+Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+
+.SH SEE ALSO
+.BR lcov (1),
+.BR lcovrc (5),
+.BR geninfo (1),
+.BR genpng (1),
+.BR gendesc (1),
+.BR gcov (1)
diff --git a/externals/lcov/man/geninfo.1 b/externals/lcov/man/geninfo.1
new file mode 100644
index 0000000000000000000000000000000000000000..2ce917126c413c54919907147202b18141062b2f
--- /dev/null
+++ b/externals/lcov/man/geninfo.1
@@ -0,0 +1,578 @@
+.TH geninfo 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.SH NAME
+geninfo \- Generate tracefiles from .da files
+.SH SYNOPSIS
+.B geninfo
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-version ]
+.RB [ \-q | \-\-quiet ]
+.br
+.RS 8
+.RB [ \-i | \-\-initial ]
+.RB [ \-t | \-\-test\-name
+.IR test\-name ]
+.br
+.RB [ \-o | \-\-output\-filename
+.IR filename ]
+.RB [ \-f | \-\-follow ]
+.br
+.RB [ \-b | \-\-base\-directory
+.IR directory ]
+.br
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-\-compat\-libtool ]
+.RB [ \-\-no\-compat\-libtool ]
+.br
+.RB [ \-\-gcov\-tool
+.IR tool  ]
+.RB [ \-\-ignore\-errors
+.IR errors  ]
+.br
+.RB [ \-\-no\-recursion ]
+.I directory
+.RB [ \-\-external ]
+.RB [ \-\-no\-external ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-no\-markers ]
+.br
+.RB [ \-\-derive\-func\-data ]
+.RB [ \-\-compat
+.IR  mode =on|off|auto]
+.br
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RB [ \-\-include
+.IR pattern ]
+.RB [ \-\-exclude
+.IR pattern ]
+.RE
+.SH DESCRIPTION
+.B geninfo 
+converts all GCOV coverage data files found in 
+.I directory
+into tracefiles, which the
+.B genhtml
+tool can convert to HTML output.
+
+Unless the \-\-output\-filename option is specified,
+.B geninfo
+writes its
+output to one file per .da file, the name of which is generated by simply
+appending ".info" to the respective .da file name.
+
+Note that the current user needs write access to both
+.I directory
+as well as to the original source code location. This is necessary because
+some temporary files have to be created there during the conversion process.
+
+Note also that
+.B geninfo
+is called from within
+.BR lcov ,
+so that there is usually no need to call it directly.
+
+.B Exclusion markers
+
+To exclude specific lines of code from a tracefile, you can add exclusion
+markers to the source code. Additionally you can exclude specific branches from
+branch coverage without excluding the involved lines from line and function
+coverage. Exclusion markers are keywords which can for example be added in the
+form of a comment.
+See
+.BR lcovrc (5)
+how to override some of them.
+
+The following markers are recognized by geninfo:
+
+LCOV_EXCL_LINE
+.RS
+Lines containing this marker will be excluded.
+.br
+.RE
+LCOV_EXCL_START
+.RS
+Marks the beginning of an excluded section. The current line is part of this
+section.
+.br
+.RE
+LCOV_EXCL_STOP
+.RS
+Marks the end of an excluded section. The current line not part of this
+section.
+.RE
+.br
+LCOV_EXCL_BR_LINE
+.RS
+Lines containing this marker will be excluded from branch coverage.
+.br
+.RE
+LCOV_EXCL_BR_START
+.RS
+Marks the beginning of a section which is excluded from branch coverage. The
+current line is part of this section.
+.br
+.RE
+LCOV_EXCL_BR_STOP
+.RS
+Marks the end of a section which is excluded from branch coverage. The current
+line not part of this section.
+.RE
+.br
+
+.SH OPTIONS
+
+.B \-b
+.I directory
+.br
+.B \-\-base\-directory
+.I directory
+.br
+.RS
+.RI "Use " directory
+as base directory for relative paths.
+
+Use this option to specify the base directory of a build\-environment
+when geninfo produces error messages like:
+
+.RS
+ERROR: could not read source file /home/user/project/subdir1/subdir2/subdir1/subdir2/file.c
+.RE
+
+In this example, use /home/user/project as base directory.
+
+This option is required when using geninfo on projects built with libtool or
+similar build environments that work with a base directory, i.e. environments,
+where the current working directory when invoking the compiler is not the same
+directory in which the source code file is located.
+
+Note that this option will not work in environments where multiple base
+directories are used. In that case use configuration file setting
+.B geninfo_auto_base=1
+(see
+.BR lcovrc (5)).
+.RE
+
+.B \-\-checksum
+.br
+.B \-\-no\-checksum
+.br
+.RS
+Specify whether to generate checksum data when writing tracefiles.
+
+Use \-\-checksum to enable checksum generation or \-\-no\-checksum to
+disable it. Checksum generation is
+.B disabled
+by default.
+
+When checksum generation is enabled, a checksum will be generated for each
+source code line and stored along with the coverage data. This checksum will
+be used to prevent attempts to combine coverage data from different source
+code versions.
+
+If you don't work with different source code versions, disable this option
+to speed up coverage data processing and to reduce the size of tracefiles.
+.RE
+
+.B \-\-compat
+.IR mode = value [, mode = value ,...]
+.br
+.RS
+Set compatibility mode.
+
+Use \-\-compat to specify that geninfo should enable one or more compatibility
+modes when capturing coverage data. You can provide a comma-separated list
+of mode=value pairs to specify the values for multiple modes.
+
+Valid
+.I values
+are:
+
+.B on
+.RS
+Enable compatibility mode.
+.RE
+.B off
+.RS
+Disable compatibility mode.
+.RE
+.B auto
+.RS
+Apply auto-detection to determine if compatibility mode is required. Note that
+auto-detection is not available for all compatibility modes.
+.RE
+
+If no value is specified, 'on' is assumed as default value.
+
+Valid
+.I modes
+are:
+
+.B libtool
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using the libtool mechanism. See also
+\-\-compat\-libtool.
+
+The default value for this setting is 'on'.
+
+.RE
+.B hammer
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 3.3 that contains a modification
+(hammer patch) of later GCC versions. You can identify a modified GCC 3.3
+by checking the build directory of your project for files ending in the
+extension '.bbg'. Unmodified versions of GCC 3.3 name these files '.bb'.
+
+The default value for this setting is 'auto'.
+
+.RE
+.B split_crc
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 4.6 that contains a modification
+(split function checksums) of later GCC versions. Typical error messages
+when running geninfo on coverage data produced by such GCC versions are
+\'out of memory' and 'reached unexpected end of file'.
+
+The default value for this setting is 'auto'
+.RE
+
+.RE
+
+.B \-\-compat\-libtool
+.br
+.B \-\-no\-compat\-libtool
+.br
+.RS
+Specify whether to enable libtool compatibility mode.
+
+Use \-\-compat\-libtool to enable libtool compatibility mode or \-\-no\-compat\-libtool
+to disable it. The libtool compatibility mode is
+.B enabled
+by default.
+
+When libtool compatibility mode is enabled, geninfo will assume that the source
+code relating to a .da file located in a directory named ".libs" can be
+found in its parent directory.
+
+If you have directories named ".libs" in your build environment but don't use
+libtool, disable this option to prevent problems when capturing coverage data.
+.RE
+
+.B \-\-config\-file
+.I config\-file
+.br
+.RS
+Specify a configuration file to use.
+
+When this option is specified, neither the system\-wide configuration file
+/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
+
+This option may be useful when there is a need to run several
+instances of
+.B geninfo
+with different configuration file options in parallel.
+.RE
+
+.B \-\-derive\-func\-data
+.br
+.RS
+Calculate function coverage data from line coverage data.
+
+Use this option to collect function coverage data, even if the version of the
+gcov tool installed on the test system does not provide this data. lcov will
+instead derive function coverage data from line coverage data and
+information about which lines belong to a function.
+.RE
+
+.B \-\-exclude
+.I pattern
+.br
+.RS
+Exclude source files matching
+.IR pattern .
+
+Use this switch if you want to exclude coverage data for a particular set
+of source files matching any of the given patterns. Multiple patterns can be
+specified by using multiple
+.B --exclude
+command line switches. The
+.I patterns
+will be interpreted as shell wildcard patterns (note that they may need to be
+escaped accordingly to prevent the shell from expanding them first).
+
+Can be combined with the
+.B --include
+command line switch. If a given file matches both the include pattern and the
+exclude pattern, the exclude pattern will take precedence.
+.RE
+
+.B \-\-external
+.br
+.B \-\-no\-external
+.br
+.RS
+Specify whether to capture coverage data for external source files.
+
+External source files are files which are not located in one of the directories
+specified by \-\-directory or \-\-base\-directory. Use \-\-external to include
+external source files while capturing coverage data or \-\-no\-external to
+ignore this data.
+
+Data for external source files is
+.B included
+by default.
+.RE
+
+.B \-f
+.br
+.B \-\-follow
+.RS
+Follow links when searching .da files.
+.RE
+
+.B \-\-gcov\-tool
+.I tool
+.br
+.RS
+Specify the location of the gcov tool.
+.RE
+
+.B \-h
+.br
+.B \-\-help
+.RS
+Print a short help text, then exit.
+.RE
+
+.B \-\-include
+.I pattern
+.br
+.RS
+Include source files matching
+.IR pattern .
+
+Use this switch if you want to include coverage data for only a particular set
+of source files matching any of the given patterns. Multiple patterns can be
+specified by using multiple
+.B --include
+command line switches. The
+.I patterns
+will be interpreted as shell wildcard patterns (note that they may need to be
+escaped accordingly to prevent the shell from expanding them first).
+.RE
+
+.B \-\-ignore\-errors
+.I errors
+.br
+.RS
+Specify a list of errors after which to continue processing.
+
+Use this option to specify a list of one or more classes of errors after which
+geninfo should continue processing instead of aborting.
+
+.I errors
+can be a comma\-separated list of the following keywords:
+
+.B gcov:
+the gcov tool returned with a non\-zero return code.
+
+.B source:
+the source code file for a data set could not be found.
+.RE
+
+.B \-i
+.br
+.B \-\-initial
+.RS
+Capture initial zero coverage data.
+
+Run geninfo with this option on the directories containing .bb, .bbg or .gcno
+files before running any test case. The result is a "baseline" coverage data
+file that contains zero coverage for every instrumented line and function.
+Combine this data file (using lcov \-a) with coverage data files captured
+after a test run to ensure that the percentage of total lines covered is
+correct even when not all object code files were loaded during the test.
+
+Note: currently, the \-\-initial option does not generate branch coverage
+information.
+.RE
+
+.B \-\-no\-markers
+.br
+.RS
+Use this option if you want to get coverage data without regard to exclusion
+markers in the source code file.
+.RE
+
+.B \-\-no\-recursion
+.br
+.RS
+Use this option if you want to get coverage data for the specified directory
+only without processing subdirectories.
+.RE
+
+.BI "\-o " output\-filename
+.br
+.BI "\-\-output\-filename " output\-filename
+.RS
+Write all data to
+.IR output\-filename .
+
+If you want to have all data written to a single file (for easier
+handling), use this option to specify the respective filename. By default,
+one tracefile will be created for each processed .da file.
+.RE
+
+.B \-q
+.br
+.B \-\-quiet
+.RS
+Do not print progress messages.
+
+Suppresses all informational progress output. When this switch is enabled,
+only error or warning messages are printed.
+.RE
+
+.B \-\-rc
+.IR keyword = value
+.br
+.RS
+Override a configuration directive.
+
+Use this option to specify a
+.IR keyword = value
+statement which overrides the corresponding configuration statement in
+the lcovrc configuration file. You can specify this option more than once
+to override multiple configuration statements.
+See
+.BR lcovrc (5)
+for a list of available keywords and their meaning.
+.RE
+
+.BI "\-t " testname
+.br
+.BI "\-\-test\-name " testname
+.RS
+Use test case name 
+.I testname
+for resulting data. Valid test case names can consist of letters, decimal
+digits and the underscore character ('_').
+
+This proves useful when data from several test cases is merged (i.e. by
+simply concatenating the respective tracefiles) in which case a test
+name can be used to differentiate between data from each test case.
+.RE
+
+.B \-v
+.br
+.B \-\-version
+.RS
+Print version number, then exit.
+.RE
+
+
+.SH FILES
+
+.I /etc/lcovrc
+.RS
+The system\-wide configuration file.
+.RE
+
+.I ~/.lcovrc
+.RS
+The per\-user configuration file.
+.RE
+
+Following is a quick description of the tracefile format as used by
+.BR genhtml ", " geninfo " and " lcov .
+
+A tracefile is made up of several human\-readable lines of text,
+divided into sections. If available, a tracefile begins with the
+.I testname
+which is stored in the following format:
+
+  TN:<test name>
+
+For each source file referenced in the .da file, there is a section containing
+filename and coverage data:
+
+  SF:<absolute path to the source file>
+
+Following is a list of line numbers for each function name found in the
+source file:
+
+  FN:<line number of function start>,<function name>
+
+Next, there is a list of execution counts for each instrumented function:
+
+  FNDA:<execution count>,<function name>
+
+This list is followed by two lines containing the number of functions found
+and hit:
+
+  FNF:<number of functions found>
+  FNH:<number of function hit>
+
+Branch coverage information is stored which one line per branch:
+
+  BRDA:<line number>,<block number>,<branch number>,<taken>
+
+Block number and branch number are gcc internal IDs for the branch. Taken is
+either '-' if the basic block containing the branch was never executed or
+a number indicating how often that branch was taken.
+
+Branch coverage summaries are stored in two lines:
+
+  BRF:<number of branches found>
+  BRH:<number of branches hit>
+
+Then there is a list of execution counts for each instrumented line
+(i.e. a line which resulted in executable code):
+
+  DA:<line number>,<execution count>[,<checksum>]
+
+Note that there may be an optional checksum present for each instrumented
+line. The current
+.B geninfo
+implementation uses an MD5 hash as checksumming algorithm.
+
+At the end of a section, there is a summary about how many lines
+were found and how many were actually instrumented:
+
+  LH:<number of lines with a non\-zero execution count>
+  LF:<number of instrumented lines>
+
+Each sections ends with:
+
+  end_of_record
+
+In addition to the main source code file there are sections for all
+#included files which also contain executable code.
+
+Note that the absolute path of a source file is generated by interpreting
+the contents of the respective .bb file (see
+.BR "gcov " (1)
+for more information on this file type). Relative filenames are prefixed
+with the directory in which the .bb file is found.
+
+Note also that symbolic links to the .bb file will be resolved so that the
+actual file path is used instead of the path to a link. This approach is
+necessary for the mechanism to work with the /proc/gcov files.
+
+.SH AUTHOR
+Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+
+.SH SEE ALSO
+.BR lcov (1),
+.BR lcovrc (5),
+.BR genhtml (1),
+.BR genpng (1),
+.BR gendesc (1),
+.BR gcov (1)
diff --git a/externals/lcov/man/genpng.1 b/externals/lcov/man/genpng.1
new file mode 100644
index 0000000000000000000000000000000000000000..f6a49b8a5d48af9f9b0c10b151592fd703ca01d4
--- /dev/null
+++ b/externals/lcov/man/genpng.1
@@ -0,0 +1,101 @@
+.TH genpng 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.SH NAME
+genpng \- Generate an overview image from a source file
+.SH SYNOPSIS
+.B genpng
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-version ]
+.RS 7
+.br
+.RB [ \-t | \-\-tab\-size
+.IR tabsize ]
+.RB [ \-w | \-\-width
+.IR width ]
+.br
+.RB [ \-o | \-\-output\-filename
+.IR output\-filename ]
+.br
+.IR source\-file
+.SH DESCRIPTION
+.B genpng
+creates an overview image for a given source code file of either
+plain text or .gcov file format.
+
+Note that the
+.I GD.pm
+Perl module has to be installed for this script to work
+(it may be obtained from
+.IR http://www.cpan.org ).
+
+Note also that
+.B genpng
+is called from within
+.B genhtml
+so that there is usually no need to call it directly.
+
+.SH OPTIONS
+.B \-h
+.br
+.B \-\-help
+.RS
+Print a short help text, then exit.
+.RE
+
+.B \-v
+.br
+.B \-\-version
+.RS
+Print version number, then exit.
+.RE
+
+.BI "\-t " tab\-size
+.br
+.BI "\-\-tab\-size " tab\-size
+.RS
+Use 
+.I tab\-size
+spaces in place of tab.
+
+All occurrences of tabulator signs in the source code file will be replaced
+by the number of spaces defined by
+.I tab\-size
+(default is 4).
+.RE
+
+.BI "\-w " width
+.br
+.BI "\-\-width " width
+.RS
+Set width of output image to 
+.I width
+pixel.
+
+The resulting image will be exactly
+.I width
+pixel wide (default is 80).
+
+Note that source code lines which are longer than
+.I width
+will be truncated.
+.RE
+
+
+.BI "\-o " filename
+.br
+.BI "\-\-output\-filename " filename
+.RS
+Write image to
+.IR filename .
+
+Specify a name for the resulting image file (default is 
+.IR source\-file .png).
+.RE
+.SH AUTHOR
+Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+
+.SH SEE ALSO
+.BR lcov (1),
+.BR genhtml (1),
+.BR geninfo (1),
+.BR gendesc (1),
+.BR gcov (1)
diff --git a/externals/lcov/man/lcov.1 b/externals/lcov/man/lcov.1
new file mode 100644
index 0000000000000000000000000000000000000000..e86eb3aa7624a76d122d791eaca2666dd41362de
--- /dev/null
+++ b/externals/lcov/man/lcov.1
@@ -0,0 +1,930 @@
+.TH lcov 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.SH NAME
+lcov \- a graphical GCOV front\-end
+.SH SYNOPSIS
+.B lcov
+.BR \-c | \-\-capture
+.RS 5
+.br
+.RB [ \-d | \-\-directory
+.IR directory ]
+.RB [ \-k | \-\-kernel\-directory
+.IR directory ]
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-t | \-\-test\-name
+.IR testname ]
+.br
+.RB [ \-b | \-\-base\-directory
+.IR directory ]
+.RB [ \-i | \-\-initial ]
+.RB [ \-\-gcov\-tool
+.IR tool ]
+.br
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.RB [ \-\-no\-recursion ]
+.RB [ \-f | \-\-follow ]
+.br
+.RB [ \-\-compat\-libtool ]
+.RB [ \-\-no\-compat\-libtool ]
+.RB [ \-\-ignore\-errors
+.IR errors ]
+.br
+.RB [ \-\-to\-package
+.IR package ]
+.RB [ \-\-from\-package
+.IR package ]
+.RB [ \-q | \-\-quiet ]
+.br
+.RB [ \-\-no\-markers ]
+.RB [ \-\-external ]
+.RB [ \-\-no\-external ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RB [ \-\-compat
+.IR  mode =on|off|auto]
+.br
+.RB [ \-\-include
+.IR pattern ]
+.RB [ \-\-exclude
+.IR pattern ]
+.br
+.RE
+
+.B lcov
+.BR \-z | \-\-zerocounters
+.RS 5
+.br
+.RB [ \-d | \-\-directory
+.IR directory ]
+.RB [ \-\-no\-recursion ]
+.RB [ \-f | \-\-follow ]
+.br
+.RB [ \-q | \-\-quiet ]
+.br
+.RE
+
+.B lcov
+.BR \-l | \-\-list
+.I tracefile
+.RS 5
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-list\-full\-path ]
+.RB [ \-\-no\-list\-full\-path ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-a | \-\-add\-tracefile
+.I tracefile
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-e | \-\-extract
+.I tracefile pattern
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-r | \-\-remove
+.I tracefile pattern
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-\-diff
+.IR "tracefile diff"
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-\-convert\-filenames ]
+.RB [ \-\-strip
+.IR depth ]
+.RB [ \-\-path
+.IR path ]
+.RB [ \-q | \-\-quiet ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-\-summary
+.I tracefile
+.RS 5
+.br
+.RB [ \-q | \-\-quiet ]
+.br
+.RE
+
+.B lcov
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-version ]
+.RS 5
+.br
+.RE
+
+.SH DESCRIPTION
+.B lcov
+is a graphical front\-end for GCC's coverage testing tool gcov. It collects
+line, function and branch coverage data for multiple source files and creates
+HTML pages containing the source code annotated with coverage information.
+It also adds overview pages for easy navigation within the file structure.
+
+Use
+.B lcov
+to collect coverage data and
+.B genhtml
+to create HTML pages. Coverage data can either be collected from the
+currently running Linux kernel or from a user space application. To do this,
+you have to complete the following preparation steps:
+
+For Linux kernel coverage:
+.RS
+Follow the setup instructions for the gcov\-kernel infrastructure:
+.I http://ltp.sourceforge.net/coverage/gcov.php
+.br
+
+
+.RE
+For user space application coverage:
+.RS
+Compile the application with GCC using the options
+"\-fprofile\-arcs" and "\-ftest\-coverage".
+.RE
+
+Please note that this man page refers to the output format of
+.B lcov
+as ".info file" or "tracefile" and that the output of GCOV
+is called ".da file".
+
+Also note that when printing percentages, 0% and 100% are only printed when
+the values are exactly 0% and 100% respectively. Other values which would
+conventionally be rounded to 0% or 100% are instead printed as nearest
+non-boundary value. This behavior is in accordance with that of the
+.BR gcov (1)
+tool.
+
+.SH OPTIONS
+
+
+.B \-a
+.I tracefile
+.br
+.B \-\-add\-tracefile
+.I tracefile
+.br
+.RS
+Add contents of
+.IR tracefile .
+
+Specify several tracefiles using the \-a switch to combine the coverage data
+contained in these files by adding up execution counts for matching test and
+filename combinations.
+
+The result of the add operation will be written to stdout or the tracefile
+specified with \-o.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+
+.RE
+
+.B \-b
+.I directory
+.br
+.B \-\-base\-directory
+.I directory
+.br
+.RS
+.RI "Use " directory
+as base directory for relative paths.
+
+Use this option to specify the base directory of a build\-environment
+when lcov produces error messages like:
+
+.RS
+ERROR: could not read source file /home/user/project/subdir1/subdir2/subdir1/subdir2/file.c
+.RE
+
+In this example, use /home/user/project as base directory.
+
+This option is required when using lcov on projects built with libtool or
+similar build environments that work with a base directory, i.e. environments,
+where the current working directory when invoking the compiler is not the same
+directory in which the source code file is located.
+
+Note that this option will not work in environments where multiple base
+directories are used. In that case use configuration file setting
+.B geninfo_auto_base=1
+(see
+.BR lcovrc (5)).
+.RE
+
+.B \-c
+.br
+.B \-\-capture
+.br
+.RS
+Capture coverage data.
+
+By default captures the current kernel execution counts and writes the
+resulting coverage data to the standard output. Use the \-\-directory
+option to capture counts for a user space program.
+
+The result of the capture operation will be written to stdout or the tracefile
+specified with \-o.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-\-checksum
+.br
+.B \-\-no\-checksum
+.br
+.RS
+Specify whether to generate checksum data when writing tracefiles.
+
+Use \-\-checksum to enable checksum generation or \-\-no\-checksum to
+disable it. Checksum generation is
+.B disabled
+by default.
+
+When checksum generation is enabled, a checksum will be generated for each
+source code line and stored along with the coverage data. This checksum will
+be used to prevent attempts to combine coverage data from different source
+code versions.
+
+If you don't work with different source code versions, disable this option
+to speed up coverage data processing and to reduce the size of tracefiles.
+.RE
+
+.B \-\-compat
+.IR mode = value [, mode = value ,...]
+.br
+.RS
+Set compatibility mode.
+
+Use \-\-compat to specify that lcov should enable one or more compatibility
+modes when capturing coverage data. You can provide a comma-separated list
+of mode=value pairs to specify the values for multiple modes.
+
+Valid
+.I values
+are:
+
+.B on
+.RS
+Enable compatibility mode.
+.RE
+.B off
+.RS
+Disable compatibility mode.
+.RE
+.B auto
+.RS
+Apply auto-detection to determine if compatibility mode is required. Note that
+auto-detection is not available for all compatibility modes.
+.RE
+
+If no value is specified, 'on' is assumed as default value.
+
+Valid
+.I modes
+are:
+
+.B libtool
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using the libtool mechanism. See also
+\-\-compat\-libtool.
+
+The default value for this setting is 'on'.
+
+.RE
+.B hammer
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 3.3 that contains a modification
+(hammer patch) of later GCC versions. You can identify a modified GCC 3.3
+by checking the build directory of your project for files ending in the
+extension '.bbg'. Unmodified versions of GCC 3.3 name these files '.bb'.
+
+The default value for this setting is 'auto'.
+
+.RE
+.B split_crc
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 4.6 that contains a modification
+(split function checksums) of later GCC versions. Typical error messages
+when running lcov on coverage data produced by such GCC versions are
+\'out of memory' and 'reached unexpected end of file'.
+
+The default value for this setting is 'auto'
+.RE
+
+.RE
+
+.B \-\-compat\-libtool
+.br
+.B \-\-no\-compat\-libtool
+.br
+.RS
+Specify whether to enable libtool compatibility mode.
+
+Use \-\-compat\-libtool to enable libtool compatibility mode or \-\-no\-compat\-libtool
+to disable it. The libtool compatibility mode is
+.B enabled
+by default.
+
+When libtool compatibility mode is enabled, lcov will assume that the source
+code relating to a .da file located in a directory named ".libs" can be
+found in its parent directory.
+
+If you have directories named ".libs" in your build environment but don't use
+libtool, disable this option to prevent problems when capturing coverage data.
+.RE
+
+.B \-\-config\-file
+.I config\-file
+.br
+.RS
+Specify a configuration file to use.
+
+When this option is specified, neither the system\-wide configuration file
+/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
+
+This option may be useful when there is a need to run several
+instances of
+.B lcov
+with different configuration file options in parallel.
+.RE
+
+.B \-\-convert\-filenames
+.br
+.RS
+Convert filenames when applying diff.
+
+Use this option together with \-\-diff to rename the file names of processed
+data sets according to the data provided by the diff.
+.RE
+
+.B \-\-diff
+.I tracefile
+.I difffile
+.br
+.RS
+Convert coverage data in
+.I tracefile
+using source code diff file
+.IR difffile .
+
+Use this option if you want to merge coverage data from different source code
+levels of a program, e.g. when you have data taken from an older version
+and want to combine it with data from a more current version.
+.B lcov
+will try to map source code lines between those versions and adjust the coverage
+data respectively.
+.I difffile
+needs to be in unified format, i.e. it has to be created using the "\-u" option
+of the
+.B diff
+tool.
+
+Note that lines which are not present in the old version will not be counted
+as instrumented, therefore tracefiles resulting from this operation should
+not be interpreted individually but together with other tracefiles taken
+from the newer version. Also keep in mind that converted coverage data should
+only be used for overview purposes as the process itself introduces a loss
+of accuracy.
+
+The result of the diff operation will be written to stdout or the tracefile
+specified with \-o.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-d
+.I directory
+.br
+.B \-\-directory
+.I  directory
+.br
+.RS
+Use .da files in
+.I directory
+instead of kernel.
+
+If you want to work on coverage data for a user space program, use this
+option to specify the location where the program was compiled (that's
+where the counter files ending with .da will be stored).
+
+Note that you may specify this option more than once.
+.RE
+
+.B \-\-exclude
+.I pattern
+.br
+.RS
+Exclude source files matching
+.IR pattern .
+
+Use this switch if you want to exclude coverage data for a particular set
+of source files matching any of the given patterns. Multiple patterns can be
+specified by using multiple
+.B --exclude
+command line switches. The
+.I patterns
+will be interpreted as shell wildcard patterns (note that they may need to be
+escaped accordingly to prevent the shell from expanding them first).
+
+Can be combined with the
+.B --include
+command line switch. If a given file matches both the include pattern and the
+exclude pattern, the exclude pattern will take precedence.
+.RE
+
+.B \-\-external
+.br
+.B \-\-no\-external
+.br
+.RS
+Specify whether to capture coverage data for external source files.
+
+External source files are files which are not located in one of the directories
+specified by \-\-directory or \-\-base\-directory. Use \-\-external to include
+external source files while capturing coverage data or \-\-no\-external to
+ignore this data.
+
+Data for external source files is
+.B included
+by default.
+.RE
+
+.B \-e
+.I tracefile
+.I pattern
+.br
+.B \-\-extract
+.I tracefile
+.I pattern
+.br
+.RS
+Extract data from
+.IR tracefile .
+
+Use this switch if you want to extract coverage data for only a particular
+set of files from a tracefile. Additional command line parameters will be
+interpreted as shell wildcard patterns (note that they may need to be
+escaped accordingly to prevent the shell from expanding them first).
+Every file entry in
+.I tracefile
+which matches at least one of those patterns will be extracted.
+
+The result of the extract operation will be written to stdout or the tracefile
+specified with \-o.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-f
+.br
+.B \-\-follow
+.br
+.RS
+Follow links when searching for .da files.
+.RE
+
+.B \-\-from\-package
+.I package
+.br
+.RS
+Use .da files in
+.I package
+instead of kernel or directory.
+
+Use this option if you have separate machines for build and test and
+want to perform the .info file creation on the build machine. See
+\-\-to\-package for more information.
+.RE
+
+.B \-\-gcov\-tool
+.I tool
+.br
+.RS
+Specify the location of the gcov tool.
+.RE
+
+.B \-h
+.br
+.B \-\-help
+.br
+.RS
+Print a short help text, then exit.
+.RE
+
+.B \-\-include
+.I pattern
+.br
+.RS
+Include source files matching
+.IR pattern .
+
+Use this switch if you want to include coverage data for only a particular set
+of source files matching any of the given patterns. Multiple patterns can be
+specified by using multiple
+.B --include
+command line switches. The
+.I patterns
+will be interpreted as shell wildcard patterns (note that they may need to be
+escaped accordingly to prevent the shell from expanding them first).
+.RE
+
+.B \-\-ignore\-errors
+.I errors
+.br
+.RS
+Specify a list of errors after which to continue processing.
+
+Use this option to specify a list of one or more classes of errors after which
+lcov should continue processing instead of aborting.
+
+.I errors
+can be a comma\-separated list of the following keywords:
+
+.B gcov:
+the gcov tool returned with a non\-zero return code.
+
+.B source:
+the source code file for a data set could not be found.
+
+.B graph:
+the graph file could not be found or is corrupted.
+.RE
+
+.B \-i
+.br
+.B \-\-initial
+.RS
+Capture initial zero coverage data.
+
+Run lcov with \-c and this option on the directories containing .bb, .bbg
+or .gcno files before running any test case. The result is a "baseline"
+coverage data file that contains zero coverage for every instrumented line.
+Combine this data file (using lcov \-a) with coverage data files captured
+after a test run to ensure that the percentage of total lines covered is
+correct even when not all source code files were loaded during the test.
+
+Recommended procedure when capturing data for a test case:
+
+1. create baseline coverage data file
+.RS
+# lcov \-c \-i \-d appdir \-o app_base.info
+.br
+
+.RE
+2. perform test
+.RS
+# appdir/test
+.br
+
+.RE
+3. create test coverage data file
+.RS
+# lcov \-c \-d appdir \-o app_test.info
+.br
+
+.RE
+4. combine baseline and test coverage data
+.RS
+# lcov \-a app_base.info \-a app_test.info \-o app_total.info
+.br
+
+.RE
+.RE
+
+.B \-k
+.I subdirectory
+.br
+.B \-\-kernel\-directory
+.I subdirectory
+.br
+.RS
+Capture kernel coverage data only from
+.IR subdirectory .
+
+Use this option if you don't want to get coverage data for all of the
+kernel, but only for specific subdirectories. This option may be specified
+more than once.
+
+Note that you may need to specify the full path to the kernel subdirectory
+depending on the version of the kernel gcov support.
+.RE
+
+.B \-l
+.I tracefile
+.br
+.B \-\-list
+.I tracefile
+.br
+.RS
+List the contents of the
+.IR tracefile .
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-\-list\-full\-path
+.br
+.B \-\-no\-list\-full\-path
+.br
+.RS
+Specify whether to show full paths during list operation.
+
+Use \-\-list\-full\-path to show full paths during list operation
+or \-\-no\-list\-full\-path to show shortened paths. Paths are
+.B shortened
+by default.
+.RE
+
+.B \-\-no\-markers
+.br
+.RS
+Use this option if you want to get coverage data without regard to exclusion
+markers in the source code file. See
+.BR "geninfo " (1)
+for details on exclusion markers.
+.RE
+
+.B \-\-no\-recursion
+.br
+.RS
+Use this option if you want to get coverage data for the specified directory
+only without processing subdirectories.
+.RE
+
+.B \-o
+.I tracefile
+.br
+.B \-\-output\-file
+.I tracefile
+.br
+.RS
+Write data to
+.I tracefile
+instead of stdout.
+
+Specify "\-" as a filename to use the standard output.
+
+By convention, lcov\-generated coverage data files are called "tracefiles" and
+should have the filename extension ".info".
+.RE
+
+.B \-\-path
+.I path
+.br
+.RS
+Strip path from filenames when applying diff.
+
+Use this option together with \-\-diff to tell lcov to disregard the specified
+initial path component when matching between tracefile and diff filenames.
+.RE
+
+.B \-q
+.br
+.B \-\-quiet
+.br
+.RS
+Do not print progress messages.
+
+This option is implied when no output filename is specified to prevent
+progress messages to mess with coverage data which is also printed to
+the standard output.
+.RE
+
+.B \-\-rc
+.IR keyword = value
+.br
+.RS
+Override a configuration directive.
+
+Use this option to specify a
+.IR keyword = value
+statement which overrides the corresponding configuration statement in
+the lcovrc configuration file. You can specify this option more than once
+to override multiple configuration statements.
+See
+.BR lcovrc (5)
+for a list of available keywords and their meaning.
+.RE
+
+.B \-r
+.I tracefile
+.I pattern
+.br
+.B \-\-remove
+.I tracefile
+.I pattern
+.br
+.RS
+Remove data from
+.IR tracefile .
+
+Use this switch if you want to remove coverage data for a particular
+set of files from a tracefile. Additional command line parameters will be
+interpreted as shell wildcard patterns (note that they may need to be
+escaped accordingly to prevent the shell from expanding them first).
+Every file entry in
+.I tracefile
+which matches at least one of those patterns will be removed.
+
+The result of the remove operation will be written to stdout or the tracefile
+specified with \-o.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-\-strip
+.I depth
+.br
+.RS
+Strip path components when applying diff.
+
+Use this option together with \-\-diff to tell lcov to disregard the specified
+number of initial directories when matching tracefile and diff filenames.
+.RE
+
+.B \-\-summary
+.I tracefile
+.br
+.RS
+Show summary coverage information for the specified tracefile.
+
+Note that you may specify this option more than once.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-t
+.I testname
+.br
+.B \-\-test\-name
+.I testname
+.br
+.RS
+Specify test name to be stored in the tracefile.
+
+This name identifies a coverage data set when more than one data set is merged
+into a combined tracefile (see option \-a).
+
+Valid test names can consist of letters, decimal digits and the underscore
+character ("_").
+.RE
+
+.B \-\-to\-package
+.I package
+.br
+.RS
+Store .da files for later processing.
+
+Use this option if you have separate machines for build and test and
+want to perform the .info file creation on the build machine. To do this,
+follow these steps:
+
+On the test machine:
+.RS
+.br
+\- run the test
+.br
+\- run lcov \-c [\-d directory] \-\-to-package
+.I file
+.br
+\- copy
+.I file
+to the build machine
+.RE
+.br
+
+On the build machine:
+.RS
+.br
+\- run lcov \-c \-\-from-package
+.I file
+[\-o and other options]
+.RE
+.br
+
+This works for both kernel and user space coverage data. Note that you might
+have to specify the path to the build directory using \-b with
+either \-\-to\-package or \-\-from-package. Note also that the package data
+must be converted to a .info file before recompiling the program or it will
+become invalid.
+.RE
+
+.B \-v
+.br
+.B \-\-version
+.br
+.RS
+Print version number, then exit.
+.RE
+
+.B \-z
+.br
+.B \-\-zerocounters
+.br
+.RS
+Reset all execution counts to zero.
+
+By default tries to reset kernel execution counts. Use the \-\-directory
+option to reset all counters of a user space program.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.SH FILES
+
+.I /etc/lcovrc
+.RS
+The system\-wide configuration file.
+.RE
+
+.I ~/.lcovrc
+.RS
+The per\-user configuration file.
+.RE
+
+.SH AUTHOR
+Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+
+.SH SEE ALSO
+.BR lcovrc (5),
+.BR genhtml (1),
+.BR geninfo (1),
+.BR genpng (1),
+.BR gendesc (1),
+.BR gcov (1)
diff --git a/externals/lcov/man/lcovrc.5 b/externals/lcov/man/lcovrc.5
new file mode 100644
index 0000000000000000000000000000000000000000..f20d273a92c8ebd48ac8a9f68498024124ef0a8f
--- /dev/null
+++ b/externals/lcov/man/lcovrc.5
@@ -0,0 +1,913 @@
+.TH lcovrc 5 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+
+.SH NAME
+lcovrc \- lcov configuration file
+
+.SH DESCRIPTION
+The
+.I lcovrc
+file contains configuration information for the
+.B lcov
+code coverage tool (see
+.BR lcov (1)).
+.br
+
+The system\-wide configuration file is located at
+.IR /etc/lcovrc .
+To change settings for a single user, place a customized copy of this file at
+location
+.IR ~/.lcovrc .
+Where available, command\-line options override configuration file settings.
+
+Lines in a configuration file can either be:
+.IP "     *"
+empty lines or lines consisting only of white space characters. These lines are
+ignored.
+.IP "     *"
+comment lines which start with a hash sign ('#'). These are treated like empty
+lines and will be ignored.
+.IP "     *"
+statements in the form
+.RI ' key " = " value '.
+A list of valid statements and their description can be found in
+section 'OPTIONS' below.
+.PP
+
+.B Example configuration:
+.IP
+#
+.br
+# Example LCOV configuration file
+.br
+#
+.br
+
+# External style sheet file
+.br
+#genhtml_css_file = gcov.css
+.br
+
+# Coverage rate limits
+.br
+genhtml_hi_limit = 90
+.br
+genhtml_med_limit = 75
+.br
+
+# Width of line coverage field in source code view
+.br
+genhtml_line_field_width = 12
+.br
+
+# Width of branch coverage field in source code view
+.br
+genhtml_branch_field_width = 16
+.br
+
+# Width of overview image
+.br
+genhtml_overview_width = 80
+.br
+
+# Resolution of overview navigation
+.br
+genhtml_nav_resolution = 4
+.br
+
+# Offset for source code navigation
+.br
+genhtml_nav_offset = 10
+.br
+
+# Do not remove unused test descriptions if non\-zero
+.br
+genhtml_keep_descriptions = 0
+.br
+
+# Do not remove prefix from directory names if non\-zero
+.br
+genhtml_no_prefix = 0
+.br
+
+# Do not create source code view if non\-zero
+.br
+genhtml_no_source = 0
+.br
+
+# Specify size of tabs
+.br
+genhtml_num_spaces = 8
+.br
+
+# Highlight lines with converted\-only data if non\-zero
+.br
+genhtml_highlight = 0
+.br
+
+# Include color legend in HTML output if non\-zero
+.br
+genhtml_legend = 0
+.br
+
+# Include HTML file at start of HTML output
+.br
+#genhtml_html_prolog = prolog.html
+.br
+
+# Include HTML file at end of HTML output
+.br
+#genhtml_html_epilog = epilog.html
+.br
+
+# Use custom HTML file extension
+.br
+#genhtml_html_extension = html
+.br
+
+# Compress all generated html files with gzip.
+.br
+#genhtml_html_gzip = 1
+.br
+
+# Include sorted overview pages
+.br
+genhtml_sort = 1
+.br
+
+# Include function coverage data display
+.br
+#genhtml_function_coverage = 1
+.br
+
+# Include branch coverage data display
+.br
+#genhtml_branch_coverage = 1
+.br
+
+# Specify the character set of all generated HTML pages
+.br
+genhtml_charset=UTF\-8
+.br
+
+# Allow HTML markup in test case description text if non\-zero
+.br
+genhtml_desc_html=0
+.br
+
+# Specify the precision for coverage rates
+.br
+#genhtml_precision=1
+.br
+
+# Show missed counts instead of hit counts
+.br
+#genhtml_missed=1
+.br
+
+# Demangle C++ symbols
+.br
+#genhtml_demangle_cpp=1
+.br
+
+# Location of the gcov tool
+.br
+#geninfo_gcov_tool = gcov
+.br
+
+# Adjust test names if non\-zero
+.br
+#geninfo_adjust_testname = 0
+.br
+
+# Calculate a checksum for each line if non\-zero
+.br
+geninfo_checksum = 0
+.br
+
+# Enable libtool compatibility mode if non\-zero
+.br
+geninfo_compat_libtool = 0
+.br
+
+# Specify whether to capture coverage data for external source
+.br
+# files
+.br
+#geninfo_external = 1
+.br
+
+# Use gcov's --all-blocks option if non-zero
+.br
+#geninfo_gcov_all_blocks = 1
+.br
+
+# Specify compatiblity modes (same as \-\-compat option
+.br
+# of geninfo)
+.br
+#geninfo_compat = libtool=on, hammer=auto, split_crc=auto
+.br
+
+# Adjust path to source files by removing or changing path
+.br
+# components that match the specified pattern (Perl regular
+.br
+# expression format)
+.br
+#geninfo_adjust_src_path = /tmp/build => /usr/src
+
+# Specify if geninfo should try to automatically determine
+.br
+# the base-directory when collecting coverage data.
+.br
+geninfo_auto_base = 1
+.br
+
+# Directory containing gcov kernel files
+.br
+lcov_gcov_dir = /proc/gcov
+.br
+
+# Location for temporary directories
+.br
+lcov_tmp_dir = /tmp
+.br
+
+# Show full paths during list operation if non\-zero
+.br
+lcov_list_full_path = 0
+.br
+
+# Specify the maximum width for list output. This value is
+.br
+# ignored when lcov_list_full_path is non\-zero.
+.br
+lcov_list_width = 80
+.br
+
+# Specify the maximum percentage of file names which may be
+.br
+# truncated when choosing a directory prefix in list output.
+.br
+# This value is ignored when lcov_list_full_path is non\-zero.
+.br
+lcov_list_truncate_max = 20
+
+# Specify if function coverage data should be collected and
+.br
+# processed.
+.br
+lcov_function_coverage = 1
+.br
+
+# Specify if branch coverage data should be collected and
+.br
+# processed.
+.br
+lcov_branch_coverage = 0
+.br
+.PP
+
+.SH OPTIONS
+
+.BR genhtml_css_file " ="
+.I filename
+.IP
+Specify an external style sheet file. Use this option to modify the appearance of the HTML output as generated by
+.BR genhtml .
+During output generation, a copy of this file will be placed in the output
+directory.
+.br
+
+This option corresponds to the \-\-css\-file command line option of
+.BR genhtml .
+.br
+
+By default, a standard CSS file is generated.
+.PP
+
+.BR genhtml_hi_limit "  ="
+.I hi_limit
+.br
+.BR genhtml_med_limit " ="
+.I med_limit
+.br
+.IP
+Specify coverage rate limits for classifying file entries. Use this option to
+modify the coverage rates (in percent) for line, function and branch coverage at
+which a result is classified as high, medium or low coverage. This
+classification affects the color of the corresponding entries on the overview
+pages of the HTML output:
+.br
+
+High:   hi_limit  <= rate <= 100        default color: green
+.br
+Medium: med_limit <= rate < hi_limit    default color: orange
+.br
+Low:    0         <= rate < med_limit   default color: red
+.br
+
+Defaults are 90 and 75 percent.
+.PP
+
+.BR genhtml_line_field_width " ="
+.I number_of_characters
+.IP
+Specify the width (in characters) of the source code view column containing
+line coverage information.
+.br
+
+Default is 12.
+.PP
+
+.BR genhtml_branch_field_width " ="
+.I number_of_characters
+.IP
+Specify the width (in characters) of the source code view column containing
+branch coverage information.
+.br
+
+Default is 16.
+.PP
+
+.BR genhtml_overview_width " ="
+.I pixel_size
+.IP
+Specify the width (in pixel) of the overview image created when generating HTML
+output using the \-\-frames option of
+.BR genhtml .
+.br
+
+Default is 80.
+.PP
+
+.BR genhtml_nav_resolution " ="
+.I lines
+.IP
+Specify the resolution of overview navigation when generating HTML output using
+the \-\-frames option of
+.BR genhtml .
+This number specifies the maximum difference in lines between the position a
+user selected from the overview and the position the source code window is
+scrolled to.
+.br
+
+Default is 4.
+.PP
+
+
+.BR genhtml_nav_offset " ="
+.I lines
+.IP
+Specify the overview navigation line offset as applied when generating HTML
+output using the \-\-frames option of
+.BR genhtml.
+.br
+
+Clicking a line in the overview image should show the source code view at
+a position a bit further up, so that the requested line is not the first
+line in the window.  This number specifies that offset.
+.br
+
+Default is 10.
+.PP
+
+
+.BR genhtml_keep_descriptions " ="
+.IR 0 | 1
+.IP
+If non\-zero, keep unused test descriptions when generating HTML output using
+.BR genhtml .
+.br
+
+This option corresponds to the \-\-keep\-descriptions option of
+.BR genhtml .
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_no_prefix " ="
+.IR 0 | 1
+.IP
+If non\-zero, do not try to find and remove a common prefix from directory names.
+.br
+
+This option corresponds to the \-\-no\-prefix option of
+.BR genhtml .
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_no_source " ="
+.IR 0 | 1
+.IP
+If non\-zero, do not create a source code view when generating HTML output using
+.BR genhtml .
+.br
+
+This option corresponds to the \-\-no\-source option of
+.BR genhtml .
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_num_spaces " ="
+.I num
+.IP
+Specify the number of spaces to use as replacement for tab characters in the
+HTML source code view as generated by
+.BR genhtml .
+.br
+
+This option corresponds to the \-\-num\-spaces option of
+.BR genthml .
+.br
+
+Default is 8.
+
+.PP
+
+.BR genhtml_highlight " ="
+.IR 0 | 1
+.IP
+If non\-zero, highlight lines with converted\-only data in
+HTML output as generated by
+.BR genhtml .
+.br
+
+This option corresponds to the \-\-highlight option of
+.BR genhtml .
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_legend " ="
+.IR 0 | 1
+.IP
+If non\-zero, include a legend explaining the meaning of color coding in the HTML
+output as generated by
+.BR genhtml .
+.br
+
+This option corresponds to the \-\-legend option of
+.BR genhtml .
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_html_prolog " ="
+.I filename
+.IP
+If set, include the contents of the specified file at the beginning of HTML
+output.
+
+This option corresponds to the \-\-html\-prolog option of
+.BR genhtml .
+.br
+
+Default is to use no extra prolog.
+.PP
+
+.BR genhtml_html_epilog " ="
+.I filename
+.IP
+If set, include the contents of the specified file at the end of HTML output.
+
+This option corresponds to the \-\-html\-epilog option of
+.BR genhtml .
+.br
+
+Default is to use no extra epilog.
+.PP
+
+.BR genhtml_html_extension " ="
+.I extension
+.IP
+If set, use the specified string as filename extension for generated HTML files.
+
+This option corresponds to the \-\-html\-extension option of
+.BR genhtml .
+.br
+
+Default extension is "html".
+.PP
+
+.BR genhtml_html_gzip " ="
+.IR 0 | 1
+.IP
+If set, compress all html files using gzip.
+
+This option corresponds to the \-\-html\-gzip option of
+.BR genhtml .
+.br
+
+Default extension is 0.
+.PP
+
+.BR genhtml_sort " ="
+.IR 0 | 1
+.IP
+If non\-zero, create overview pages sorted by coverage rates when generating
+HTML output using
+.BR genhtml .
+.br
+
+This option can be set to 0 by using the \-\-no\-sort option of
+.BR genhtml .
+.br
+
+Default is 1.
+.PP
+
+.BR genhtml_function_coverage " ="
+.IR 0 | 1
+.IP
+If non\-zero, include function coverage data when generating HTML output using
+.BR genhtml .
+.br
+
+This option can be set to 0 by using the \-\-no\-function\-coverage option of
+.BR genhtml .
+.br
+
+Default is 1.
+.PP
+
+.BR genhtml_branch_coverage " ="
+.IR 0 | 1
+.IP
+If non\-zero, include branch coverage data when generating HTML output using
+.BR genhtml .
+.br
+
+This option can be set to 0 by using the \-\-no\-branch\-coverage option of
+.BR genhtml .
+.br
+
+Default is 1.
+.PP
+
+.BR genhtml_charset " ="
+.I charset
+.IP
+Specify the character set of all generated HTML pages.
+.br
+
+Use this option if the source code contains characters which are not
+part of the default character set. Note that this option is ignored
+when a custom HTML prolog is specified (see also
+.BR genhtml_html_prolog ).
+.br
+
+Default is UTF-8.
+.PP
+
+.BR genhtml_demangle_cpp " ="
+.IR 0 | 1
+.IP
+If non-zero, demangle C++ function names in function overviews.
+
+Set this option to one if you want to convert C++ internal function
+names to human readable format for display on the HTML function overview
+page.  This option requires that the c++filt tool is installed (see
+.BR c++filt(1)
+).
+.br
+
+This option corresponds to the \-\-demangle\-cpp command line option of
+.BR genhtml .
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_desc_html " ="
+.IR 0 | 1
+.IP
+If non-zero, test case descriptions may contain HTML markup.
+
+Set this option to one if you want to embed HTML markup (for example to
+include links) in test case descriptions. When set to zero, HTML markup
+characters will be escaped to show up as plain text on the test case
+description page.
+.br
+
+Default is 0.
+.PP
+
+.BR genhtml_precision " ="
+.IR  1 | 2 | 3 | 4
+.IP
+Specify how many digits after the decimal-point should be used for
+displaying coverage rates.
+.br
+
+Default is 1.
+.PP
+.BR genhtml_missed " ="
+.IR  0 | 1
+.IP
+If non-zero, the count of missed lines, functions, or branches is shown
+as negative numbers in overview pages.
+.br
+
+Default is 0.
+.PP
+
+.
+.BR geninfo_gcov_tool " ="
+.I path_to_gcov
+.IP
+Specify the location of the gcov tool (see
+.BR gcov (1))
+which is used to generate coverage information from data files. 
+.br
+
+Default is 'gcov'.
+.PP
+
+.BR geninfo_adjust_testname " ="
+.IR 0 | 1
+.IP
+If non\-zero,  adjust test names to include operating system information
+when capturing coverage data.
+.br
+
+Default is 0.
+.PP
+
+.BR geninfo_checksum " ="
+.IR 0 | 1
+.IP
+If non\-zero, generate source code checksums when capturing coverage data.
+Checksums are useful to prevent merging coverage data from incompatible
+source code versions but checksum generation increases the size of coverage
+files and the time used to generate those files.
+.br
+
+This option corresponds to the \-\-checksum and \-\-no\-checksum command line
+option of
+.BR geninfo .
+.br
+
+Default is 0.
+.PP
+
+.BR geninfo_compat_libtool " ="
+.IR 0 | 1
+.IP
+If non\-zero, enable libtool compatibility mode. When libtool compatibility
+mode is enabled, lcov will assume that the source code relating to a .da file
+located in a directory named ".libs" can be found in its parent directory.
+.br
+
+This option corresponds to the \-\-compat\-libtool and \-\-no\-compat\-libtool
+command line option of
+.BR geninfo .
+.br
+
+Default is 1.
+.PP
+
+.BR geninfo_external " ="
+.IR 0 | 1
+.IP
+If non\-zero, capture coverage data for external source files.
+
+External source files are files which are not located in one of the directories
+(including sub-directories)
+specified by the \-\-directory or \-\-base\-directory options of
+.BR lcov / geninfo .
+
+Default is 1.
+.PP
+
+.BR geninfo_gcov_all_blocks " ="
+.IR 0 | 1
+.IP
+If non\-zero, call the gcov tool with option --all-blocks.
+
+Using --all-blocks will produce more detailed branch coverage information for
+each line. Set this option to zero if you do not need detailed branch coverage
+information to speed up the process of capturing code coverage or to work
+around a bug in some versions of gcov which will cause it to endlessly loop
+when analysing some files.
+
+Default is 1.
+.PP
+
+.BR geninfo_compat " ="
+.IR mode = value [, mode = value ,...]
+.IP
+Specify that geninfo should enable one or more compatibility modes
+when capturing coverage data.
+
+This option corresponds to the \-\-compat command line option of
+.BR geninfo .
+
+Default is 'libtool=on, hammer=auto, split_crc=auto'.
+.PP
+
+.BR geninfo_adjust_src_path " ="
+.IR pattern " => " replacement
+.br
+.BR geninfo_adjust_src_path " ="
+.I pattern
+.IP
+Adjust source paths when capturing coverage data.
+
+Use this option in situations where geninfo cannot find the correct
+path to source code files of a project. By providing a
+.I pattern
+in Perl regular expression format (see
+.BR perlre (1))
+and an optional replacement string, you can instruct geninfo to
+remove or change parts of the incorrect source path.
+
+.B Example:
+.br
+
+1. When geninfo reports that it cannot find source file
+.br
+
+    /path/to/src/.libs/file.c
+.br
+
+while the file is actually located in
+.br
+
+    /path/to/src/file.c
+.br
+
+use the following parameter:
+.br
+
+    geninfo_adjust_src_path = /.libs
+
+This will remove all "/.libs" strings from the path.
+
+2. When geninfo reports that it cannot find source file
+.br
+
+    /tmp/build/file.c
+.br
+
+while the file is actually located in
+.br
+
+    /usr/src/file.c
+.br
+
+use the following parameter:
+.br
+
+    geninfo_adjust_src_path = /tmp/build => /usr/src
+.br
+
+This will change all "/tmp/build" strings in the path to "/usr/src".
+.PP
+
+.BR geninfo_auto_base " ="
+.IR 0 | 1
+.IP
+If non\-zero, apply a heuristic to determine the base directory when
+collecting coverage data.
+.br
+
+Use this option when using geninfo on projects built with libtool or
+similar build environments that work with multiple base directories,
+i.e. environments, where the current working directory when invoking the
+compiler ist not the same directory in which the source code file is
+located, and in addition, is different between files of the same project.
+.br
+
+Default is 1.
+.PP
+
+.BR lcov_gcov_dir " ="
+.I path_to_kernel_coverage_data
+.IP
+Specify the path to the directory where kernel coverage data can be found
+or leave undefined for auto-detection.
+.br
+
+Default is auto-detection.
+.PP
+
+.BR lcov_tmp_dir " ="
+.I temp
+.IP
+Specify the location of a directory used for temporary files.
+.br
+
+Default is '/tmp'.
+.PP
+
+.BR lcov_list_full_path " ="
+.IR 0 | 1
+.IP
+If non-zero, print the full path to source code files during a list operation.
+.br
+
+This option corresponds to the \-\-list\-full\-path option of
+.BR lcov .
+.br
+
+Default is 0.
+.PP
+
+.BR lcov_list_max_width " ="
+.IR width
+.IP
+Specify the maximum width for list output. This value is ignored when
+lcov_list_full_path is non\-zero.
+.br
+
+Default is 80.
+.PP
+
+.BR lcov_list_truncate_max
+.B " ="
+.IR percentage
+.IP
+Specify the maximum percentage of file names which may be truncated when
+choosing a directory prefix in list output. This value is ignored when
+lcov_list_full_path is non\-zero.
+.br
+
+Default is 20.
+.PP
+
+.BR lcov_function_coverage " ="
+.IR 0 | 1
+.IP
+Specify whether lcov should handle function coverage data.
+.br
+
+Setting this option to 0 can reduce memory and CPU time consumption
+when lcov is collecting and processing coverage data, as well as
+reduce the size of the resulting data files. Note that setting
+.B genhtml_function_coverage
+will override this option for HTML generation.
+.br
+
+Default is 1.
+.PP
+
+.BR lcov_branch_coverage " ="
+.IR 0 | 1
+.IP
+Specify whether lcov should handle branch coverage data.
+.br
+
+Setting this option to 0 can reduce memory and CPU time consumption
+when lcov is collecting and processing coverage data, as well as
+reduce the size of the resulting data files. Note that setting
+.B genhtml_branch_coverage
+will override this option for HTML generation.
+.br
+
+Default is 0.
+.PP
+
+.BR lcov_excl_line " ="
+.I expression
+.IP
+Specify the regular expression of lines to exclude.
+.br
+
+Default is 'LCOV_EXCL_LINE'.
+.PP
+
+.BR lcov_excl_br_line " ="
+.I expression
+.IP
+Specify the regular expression of lines to exclude from branch coverage.
+.br
+
+Default is 'LCOV_EXCL_BR_LINE'.
+.PP
+
+.SH FILES
+
+.TP
+.I /etc/lcovrc
+The system\-wide
+.B lcov
+configuration file.
+
+.TP
+.I ~/.lcovrc
+The individual per\-user configuration file.
+.PP
+
+.SH SEE ALSO
+.BR lcov (1),
+.BR genhtml (1),
+.BR geninfo (1),
+.BR gcov (1)
diff --git a/externals/lcov/rpm/lcov.spec b/externals/lcov/rpm/lcov.spec
new file mode 100644
index 0000000000000000000000000000000000000000..e96c8d47bd08ce9c2c185c0ac417f88b1e25e77f
--- /dev/null
+++ b/externals/lcov/rpm/lcov.spec
@@ -0,0 +1,59 @@
+Summary: A graphical GCOV front-end
+Name: lcov
+Version: 1.14
+Release: 1
+License: GPLv2+
+Group: Development/Tools
+URL: http://ltp.sourceforge.net/coverage/lcov.php
+Source0: http://downloads.sourceforge.net/ltp/%{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+BuildArch: noarch
+Requires: perl >= 5.8.8
+
+%description
+LCOV is a graphical front-end for GCC's coverage testing tool gcov. It collects
+gcov data for multiple source files and creates HTML pages containing the
+source code annotated with coverage information. It also adds overview pages
+for easy navigation within the file structure.
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+exit 0
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr CFG_DIR=/etc
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+/usr/bin/*
+/usr/share/man/man*/*
+%config /etc/*
+
+%changelog
+* Mon Aug 22 2016 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- updated "make install" call to work with PREFIX Makefile changes
+
+* Mon May 07 2012 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- added dependency on perl 5.8.8 for >>& open mode support
+
+* Wed Aug 13 2008 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- changed description + summary text
+
+* Mon Aug 20 2007 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- fixed "Copyright" tag
+
+* Mon Jul 14 2003 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- removed variables for version/release to support source rpm building
+- added initial rm command in install section
+
+* Mon Apr 7 2003 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- implemented variables for version/release
+
+* Fri Oct 18 2002 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- created initial spec file
diff --git a/externals/lcov/test/Makefile b/externals/lcov/test/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ecb96042aab0bb2aa802cb9316323e2f384e7929
--- /dev/null
+++ b/externals/lcov/test/Makefile
@@ -0,0 +1,27 @@
+include common.mak
+
+TESTDIRS   := $(sort $(patsubst %/,%,$(dir $(wildcard */Makefile))))
+
+help: info
+
+info:
+	echo "Available make targets:"
+	echo "  test   : perform self-tests"
+	echo "  clean  : remove all temporary files"
+	echo ""
+	echo "Available make variables:"
+	echo "  SIZE   : specify size of test data (small, medium, large)"
+	echo "  V      : specify level of verbosity (0, 1, 2)"
+
+test:
+	for TEST in $(TESTDIRS) ; do \
+		make -C $$TEST test ; \
+	done
+
+clean:
+	rm -rf *.info *.counts test.log src/
+	for TEST in $(TESTDIRS) ; do \
+		make -C $$TEST clean ; \
+	done
+
+.PHONY: help info test clean
diff --git a/externals/lcov/test/bin/common b/externals/lcov/test/bin/common
new file mode 100644
index 0000000000000000000000000000000000000000..a8b527deda0567c093e3bceebe286ecbb4c8c6c6
--- /dev/null
+++ b/externals/lcov/test/bin/common
@@ -0,0 +1,103 @@
+function elapsed_to_ms()
+{
+	local ELAPSED=$1
+	local IFS=:.
+	local MS
+
+	set -- $ELAPSED
+	if [ $# -eq 3 ] ; then
+		let MS=${3#0}*10+${2#0}*1000+$1*60000
+	else
+		let MS=${4#0}*10+${3#0}*1000+${2#0}*60000+$1*3600000
+	fi
+
+	echo $MS
+}
+
+function t_timestamp()
+{
+	date +"%Y-%m-%d %H:%M:%S %z"
+}
+
+function t_marker()
+{
+	echo
+	echo "======================================================================"
+}
+
+function t_detail()
+{
+	local KEY=$1
+	local VALUE=$2
+	local DOTS=" ............"
+
+	printf "%-.12s: %s\n" "$KEY$DOTS" "$VALUE"
+}
+
+function t_announce()
+{
+	local TESTNAME="$1"
+
+	printf "$BOLD%-.30s$RESET " "$TESTNAME .............................."
+	t_marker >> "$LOGFILE"
+	t_detail "DATE" "$(t_timestamp)" >> "$LOGFILE"
+	t_detail "TESTNAME" "$TESTNAME" >> "$LOGFILE"
+}
+
+function t_result()
+{
+	local COLOR="$1"
+	local TEXT="$2"
+
+	printf "[$COLOR$TEXT$RESET]"
+}
+
+function t_pass()
+{
+	local TESTNAME="$1"
+
+	t_result "$GREEN" "pass"
+	echo "pass $TESTNAME" >> "$COUNTFILE"
+}
+
+function t_fail()
+{
+	local TESTNAME="$1"
+
+	t_result "$RED" "fail"
+	echo "fail $TESTNAME" >> "$COUNTFILE"
+}
+
+function t_kill()
+{
+	local TESTNAME="$1"
+
+	t_result "$RED" "kill"
+	echo "fail $TESTNAME" >> "$COUNTFILE"
+}
+
+function t_skip()
+{
+	local TESTNAME="$1"
+
+	t_result "$BLUE" "skip"
+	echo "skip $TESTNAME" >> "$COUNTFILE"
+}
+
+function t_indent()
+{
+	sed -e 's/^/  /'
+}
+
+LOGFILE="$TOPDIR/test.log"
+COUNTFILE="$TOPDIR/test.counts"
+TIMEFILE="$TOPDIR/test.time"
+
+if [ -t 1 ] ; then
+	RED="\e[31m"
+	GREEN="\e[32m"
+	BLUE="\e[34m"
+	BOLD="\e[1m"
+	DEFAULT="\e[39m"
+	RESET="\e[0m"
+fi
diff --git a/externals/lcov/test/bin/mkinfo b/externals/lcov/test/bin/mkinfo
new file mode 100755
index 0000000000000000000000000000000000000000..5231aeac5d12ce32f2230581a9741f354a19bdd1
--- /dev/null
+++ b/externals/lcov/test/bin/mkinfo
@@ -0,0 +1,952 @@
+#!/usr/bin/env perl
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: mkinfo <config_file> [-o <output_dir>] [--seed <seed>]
+#               [<key>=<value>...]
+# 
+# Create a fake lcov code coverage data file and optionally the corresponding
+# source tree. DATA_FILE contains all specifications for creating the data
+# file. Directives can be overridden using KEY=VALUE specifications with KEY
+# being in the form SECTION.KEY. SEED specifies the number used to initialize
+# the pseudo random number generator.
+# 
+# Example:
+# mkinfo profiles/small -o src files.numfiles=12
+#
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use Cwd qw(abs_path getcwd);
+use File::Path qw(make_path);
+use File::Basename;
+use Data::Dumper;
+
+my $MAX_TAKEN	= 1000;
+my $use_colors	= -t STDIN;
+my $BOLD	= $use_colors ? "\033[1m" : "";
+my $RESET	= $use_colors ? "\033[0m" : "";
+
+sub usage()
+{
+	print(<<EOF)
+Usage: $0 <config_file> [-o <output_dir>] [--seed <seed>] [<key>=<value>...]
+
+Create a fake lcov code coverage data file and optionally the corresponding
+source tree. DATA_FILE contains all specifications for creating the data
+file. Directives can be overridden using KEY=VALUE specifications with KEY
+being in the form SECTION.KEY. SEED specifies the number used to initialize
+the pseudo random number generator.
+ 
+Example:
+$0 profiles/small -o src files.numfiles=12
+EOF
+}
+
+sub read_config($)
+{
+	my ($filename) = @_;
+	my $fd;
+	my %config;
+	my $section;
+
+	open($fd, "<", $filename) or die("Could not open $filename: $!\n");
+	while (my $line = <$fd>) {
+		my ($key, $value);
+
+		$line =~ s/(^\s*|\s*$)//g;
+		next if ($line eq "" || $line =~ /^#/);
+		if ($line =~ /^\[\s*(\S+)\s*]$/) {
+			$section = $1;
+			next;
+		}
+		if ($line !~ /^(\S+)\s*=\s*(.*)$/) {
+			die("$filename:$.: Unknown line format: $line\n");
+		}
+		($key, $value) = ($1, $2);
+		if (!defined($section)) {
+			die("$filename:$.: Directive outside of section\n");
+		}
+		$config{$section}->{$1} = $2;
+	}
+	close($fd);
+
+	return \%config;
+}
+
+sub apply_config($$)
+{
+	my ($config, $directive) = @_;
+
+	for my $dir (@$directive) {
+		if ($dir !~ /^([^\.]+)\.([^=]+)=(.*)$/) {
+			die("Unknown directive format: $dir\n");
+		}
+		$config->{$1}->{$2} = $3;
+	}
+}
+
+sub get_value($$;$)
+{
+	my ($config, $dir, $default) = @_;
+	my ($section, $key, $value);
+
+	if ($dir !~ /^([^\.]+)\.([^=]+)$/) {
+		die("$0: Internal error: Unknown key format: $key\n");
+	}
+	($section, $key) = ($1, $2);
+
+	$value = $config->{$section}->{$key};
+
+	if (!defined($value)) {
+		if (!defined($default)) {
+			die("$0: Missing config value for $dir\n");
+		}
+		$value = $default;
+	}
+
+	return $value;
+}
+
+sub get_int($$;$$$)
+{
+	my ($config, $dir, $default, $min, $max) = @_;
+	my $value = get_value($config, $dir, $default);
+
+	if ($value !~ /^\d+$/) {
+		die("$0: Config value $dir must be an integer: $value\n");
+	}
+	$value = int($value);
+	if (defined($min) && $value < $min) {
+		die("$0: Config value $dir is too low (min $min): $value\n");
+	}
+	if (defined($max) && $value > $max) {
+		die("$0: Config value $dir is too high (max $max): $value\n");
+	}
+
+	return int($value);
+}
+
+sub get_list($$;$)
+{
+	my ($config, $dir, $default) = @_;
+	my $value = get_value($config, $dir, $default);
+	my @list = split(/\s+/, $value);
+
+	return \@list;
+}
+
+sub randlist($)
+{
+	my ($list) = @_;
+
+	return "" if (!@$list);
+	return $list->[int(rand(scalar(@$list)))];
+}
+
+sub randbool()
+{
+	return int(rand(2));
+}
+
+# Reduce LIST to PERCENTAGE of its former size.
+sub reduce_list_per($$)
+{
+	my ($list, $percentage) = @_;
+	my $remove;
+
+	$remove = int((100 - $percentage) * scalar(@$list) / 100);
+
+	for (my $i = 0; $i < $remove; $i++) {
+		splice(@$list, int(rand(scalar(@$list))), 1);
+	}
+}
+
+# Reduce LIST to NUM items.
+sub reduce_list_num($$)
+{
+	my ($list, $num) = @_;
+	my $remove;
+
+	$remove = scalar(@$list) - $num;
+
+	for (my $i = 0; $i < $remove; $i++) {
+		splice(@$list, int(rand(scalar(@$list))), 1);
+	}
+}
+
+sub _gen_filename($$)
+{
+	my ($c, $root) = @_;
+	my $ltop = get_list($c, "files.top", "");
+	my $lsub = get_list($c, "files.sub", "");
+	my $lsubsub = get_list($c, "files.subsub", "");
+	my $lprefix = get_list($c, "files.prefix");
+	my $lsuffix = get_list($c, "files.suffix", "");
+	my $lext = get_list($c, "files.ext");
+	my ($top, $sub, $subsub, $prefix, $suffix, $ext) =
+		("", "", "", "", "", "");
+	my $filename = "";
+
+	$top = randlist($ltop) if (randbool());
+	$sub = randlist($lsub) if (randbool());
+	$subsub = randlist($lsubsub) if (randbool());
+	$prefix = randlist($lprefix);
+	$suffix = randlist($lsuffix) if (randbool());
+	$ext = randlist($lext);
+
+	$filename = $root;
+	$filename .= "/".$top if ($top ne "");
+	$filename .= "/".$sub if ($sub ne "");
+	$filename .= "/".$subsub if ($subsub ne "");
+	$filename .= "/".$prefix;
+	$filename .= "_".$suffix if ($suffix ne "");
+	$filename .= $ext;
+	$filename =~ s#^//#/#;
+
+	return $filename;
+}
+
+sub gen_filename($$$)
+{
+	my ($c, $root, $filenames) = @_;
+	my $filename;
+
+	do {
+		$filename = _gen_filename($c, $root);
+	} while ($filenames->{$filename});
+	$filenames->{$filename} = 1;
+
+	return $filename;
+}
+
+sub gen_lines($$)
+{
+	my ($c, $length) = @_;
+	my @lines = 1 .. $length;
+	my $percent = get_int($c, "lines.instrumented", undef, 0, 100);
+
+	reduce_list_per(\@lines, $percent);
+
+	return \@lines;
+}
+
+sub gen_fnname($$)
+{
+	my ($c, $hash) = @_;
+	my $lverb = get_list($c, "functions.verb");
+	my $ladj = get_list($c, "functions.adj", "");
+	my $lnoun = get_list($c, "functions.noun", "");
+	my ($verb, $adj, $noun) = ("", "", "");
+	my $fnname;
+
+	$verb = randlist($lverb);
+	$adj = randlist($ladj) if (randbool());
+	$noun = randlist($lnoun) if (randbool());
+
+	$fnname = $verb;
+	$fnname .= "_".$adj if ($adj ne "");
+	$fnname .= "_".$noun if ($noun ne "");
+
+	if (exists($hash->{$fnname})) {
+		my $i = 2;
+
+		while (exists($hash->{$fnname.$i})) {
+			$i++;
+		}
+		$fnname .= $i;
+	}
+	$hash->{$fnname} = 1;
+
+	return $fnname;
+}
+
+sub gen_functions($$)
+{
+	my ($c, $lines) = @_;
+	my @fnlines;
+	my @functions;
+	my %names;
+	my $percent = get_int($c, "functions.perinstrumented", undef, 0, 100);
+
+	@fnlines = @$lines;
+	reduce_list_per(\@fnlines, $percent);
+
+	foreach my $fnline (@fnlines) {
+		push(@functions, [ $fnline, gen_fnname($c, \%names) ]);
+	}
+
+	return \@functions;
+}
+
+
+# Returns a value distribution object. This object can be used to randomly
+# choose one element from a list of elements with a given relative distribution.
+#
+# dist: [ sumprob, probs]
+# sumprob: Sum of all probabilities
+# probs: [ prob1, prob2, ... ]
+# prob: [ num, x ]
+# num: Value
+sub get_dist($$;$)
+{
+	my ($c, $dir, $default) = @_;
+	my $list = get_list($c, $dir, $default);
+	my $sumprob = 0;
+	my @probs;
+
+	foreach my $spec (@$list) {
+		my ($n, $p);
+
+		if ($spec =~ /^(\d+):(\d+)$/) {
+			($n, $p) = ($1, $2);
+		} elsif ($spec =~ /^(\d+)$/) {
+			$n = $1;
+			$p = 1;
+		} else {
+			die("$0: Config value $dir must be a distribution ".
+			    "list (a:p1 b:p2 ...)\n");
+		}
+		$sumprob += $p;
+		push(@probs, [ $n, $sumprob ]);
+	}
+
+	return [ $sumprob, \@probs ];
+}
+
+sub rand_dist($)
+{
+	my ($dist) = @_;
+	my ($sumprob, $probs) = @$dist;
+	my $r = int(rand($sumprob));
+
+	foreach my $prob (@$probs) {
+		my ($num, $x) = @$prob;
+		return $num if ($r < $x);
+	}
+
+	die("Internal error: Incomplete distribution list\n");
+}
+
+sub gen_branches($$)
+{
+	my ($c, $lines) = @_;
+	my $percent = get_int($c, "branches.perinstrumented", undef, 0, 100);
+	my @allblocks = @{get_list($c, "branches.blocks", "0")};
+	my $branchdist = get_dist($c, "branches.branchdist", "2");
+	my @brlines;
+	my @branches;
+
+	@brlines = @$lines;
+	reduce_list_per(\@brlines, $percent);
+
+	foreach my $brline (@brlines) {
+		my @blocks = @allblocks;
+		my $numblocks = int(rand(scalar(@blocks))) + 1;
+
+		reduce_list_num(\@blocks, $numblocks);
+
+		foreach my $block (@blocks) {
+			my $numbranch = rand_dist($branchdist);
+
+			for (my $branch = 0; $branch < $numbranch; $branch++) {
+				push(@branches, [ $brline, $block, $branch]);
+			}
+		}
+	}
+
+	return \@branches;
+}
+
+sub gen_filesrc($)
+{
+	my ($c) = @_;
+	my ($length, $lines, $functions, $branches);
+	my $do_ln = get_int($c, "lines.enabled");
+	my $do_fn = get_int($c, "functions.enabled");
+	my $do_br = get_int($c, "branches.enabled");
+
+	$length		= 1 + int(rand(get_int($c, "lines.maxlines")));
+	$lines		= gen_lines($c, $length);
+	$functions	= gen_functions($c, $lines) if ($do_fn);
+	$branches	= gen_branches($c, $lines) if ($do_br);
+
+	return [ $length, $lines, $functions, $branches ];
+}
+
+# Generate fake source tree.
+#
+# returns:	[ files, numlns, numfns, numbrs ]
+# files:	filename -> filesrc
+# filesrc:	[ length, lines, functions, branches ]
+# length:	Total number of lines in file
+#
+# lines:	[ line1, line2, ... ]
+#
+# functions:	[ fn1, fn2, ... ]
+# fn:		[ fnline, fnname ]
+# fnline:	Starting line of function
+# fnname:	Function name
+#
+# branches:	[ brdata1, brdata2, ...]
+# brdata:	[ brline, block, branch ]
+# brline:	Line number containing branches
+# block:	Block ID
+# branch:	Branch ID
+#
+sub gen_src($$)
+{
+	my ($c, $root) = @_;
+	my %files;
+	my $numfiles = get_int($c, "files.numfiles");
+	my %filenames;
+	my ($numlns, $numfns, $numbrs) = (0, 0, 0);
+
+	for (my $i = 0; $i < $numfiles; $i++) {
+		my $filename = gen_filename($c, $root, \%filenames);
+		my $filesrc = gen_filesrc($c);
+
+		$files{$filename} = $filesrc;
+		$numlns += scalar(@{$filesrc->[1]}) if (defined($filesrc->[1]));
+		$numfns += scalar(@{$filesrc->[2]}) if (defined($filesrc->[2]));
+		$numbrs += scalar(@{$filesrc->[3]}) if (defined($filesrc->[3]));
+	}
+
+	return [ \%files, $numlns, $numfns, $numbrs ];
+}
+
+sub write_src($)
+{
+	my ($src) = @_;
+	my ($files, $numlns, $numfns, $numbrs) = @$src;
+
+	foreach my $filename (sort(keys(%{$files}))) {
+		my $filesrc = $files->{$filename};
+		my $length = $filesrc->[0];
+		my $dir = dirname($filename);
+		my $fd;
+
+		if (!-d $dir) {
+			make_path($dir) or
+				die("Could not create directory $dir\n");
+		}
+
+		open($fd, ">", $filename) or
+			die("Could not create file $filename: $!\n");
+		for (my $i = 0; $i < $length; $i++) {
+			print($fd "\n");
+		}
+		close($fd);
+	}
+}
+
+sub write_branches($$$$)
+{
+	my ($fd, $branches, $brhits, $iref) = @_;
+	my ($found, $hit) = (0, 0);
+
+	# Line coverage data
+	foreach my $brdata (@$branches) {
+		my $brhit = $brhits->[$$iref++];
+		my ($brline, $block, $branch) = @$brdata;
+
+		$found++;
+		$hit++ if ($brhit ne "-" && $brhit > 0);
+		print($fd "BRDA:$brline,$block,$branch,$brhit\n");
+	}
+	if ($found > 0) {
+		print($fd "BRF:$found\n");
+		print($fd "BRH:$hit\n");
+	}
+}
+
+sub write_lines($$$$)
+{
+	my ($fd, $lines, $lnhist, $iref) = @_;
+	my ($found, $hit) = (0, 0);
+
+	# Line coverage data
+	foreach my $line (@$lines) {
+		my $lnhit = $lnhist->[$$iref++];
+
+		$found++;
+		$hit++ if ($lnhit > 0);
+		print($fd "DA:$line,$lnhit\n");
+	}
+	print($fd "LF:$found\n");
+	print($fd "LH:$hit\n");
+}
+
+sub write_functions($$$$)
+{
+	my ($fd, $functions, $fnhits, $iref) = @_;
+	my ($found, $hit) = (0, 0);
+
+	# Function coverage data
+	foreach my $fn (@$functions) {
+		my ($fnline, $fnname) = @$fn;
+
+		print($fd "FN:$fnline,$fnname\n");
+	}
+	foreach my $fn (@$functions) {
+		my ($fnline, $fnname) = @$fn;
+		my $fnhit = $fnhits->[$$iref++];
+
+		$found++;
+		$hit++ if ($fnhit > 0);
+		print($fd "FNDA:$fnhit,$fnname\n");
+	}
+	print($fd "FNF:$found\n");
+	print($fd "FNH:$hit\n");
+}
+
+sub write_filesrc($$$$$)
+{
+	my ($c, $fd, $filesrc, $hits, $iter) = @_;
+	my ($length, $lines, $functions, $branches) = @$filesrc;
+	my $do_ln = get_int($c, "lines.enabled");
+	my $do_fn = get_int($c, "functions.enabled");
+	my $do_br = get_int($c, "branches.enabled");
+
+	write_functions($fd, $functions, $hits->[1], \$iter->[1]) if ($do_fn);
+	write_branches($fd, $branches, $hits->[2], \$iter->[2]) if ($do_br);
+	write_lines($fd, $lines, $hits->[0], \$iter->[0]) if ($do_ln);
+}
+
+sub write_info($$$$)
+{
+	my ($c, $filename, $src, $hits) = @_;
+	my $files = $src->[0];
+	my $fd;
+	my %iters;
+
+	foreach my $testname (keys(%{$hits})) {
+		$iters{$testname} = [ 0, 0, 0 ];
+	}
+
+	open($fd, ">", $filename) or die("Could not create $filename: $!\n");
+
+	foreach my $filename (sort(keys(%{$files}))) {
+		my $filesrc = $files->{$filename};
+
+		foreach my $testname (sort(keys(%{$hits}))) {
+			my $testhits = $hits->{$testname};
+			my $iter = $iters{$testname};
+
+			print($fd "TN:$testname\n");
+			print($fd "SF:$filename\n");
+
+			write_filesrc($c, $fd, $filesrc, $testhits, $iter);
+
+			print($fd "end_of_record\n");
+		}
+	}
+
+	close($fd);
+}
+
+sub get_hit_found($)
+{
+	my ($list) = @_;
+	my ($hit, $found) = (0, 0);
+
+	foreach my $e (@$list) {
+		$hit++ if ($e ne "-" && $e > 0);
+		$found++;
+	}
+	return ($hit, $found);
+}
+
+sub write_counts($$)
+{
+	my ($filename, $hits) = @_;
+	my $fd;
+	my (@tlnhits, @tfnhits, @tbrhits);
+
+	foreach my $testname (keys(%{$hits})) {
+		my $testhits = $hits->{$testname};
+		my ($lnhits, $fnhits, $brhits) = @$testhits;
+
+		for (my $i = 0; $i < scalar(@$lnhits); $i++) {
+			$tlnhits[$i] += $lnhits->[$i];
+		}
+		for (my $i = 0; $i < scalar(@$fnhits); $i++) {
+			$tfnhits[$i] += $fnhits->[$i];
+		}
+		for (my $i = 0; $i < scalar(@$brhits); $i++) {
+			my $h = $brhits->[$i];
+
+			$h = 0 if ($h eq "-");
+			$tbrhits[$i] += $h;
+		}
+	}
+
+	open($fd, ">", $filename) or die("Could not create $filename: $!\n");
+	print($fd join(" ", get_hit_found(\@tlnhits), get_hit_found(\@tfnhits),
+			    get_hit_found(\@tbrhits))."\n");
+	close($fd);
+}
+
+# A branch hit value for a block that was not hit must be "-". A branch hit
+# value for a block that was hit cannot be "-", but must be "0" if not hit.
+sub sanitize_brhits($)
+{
+	my ($brhits) = @_;
+	my $block_hit = 0;
+
+	foreach my $brhit_ref (@$brhits) {
+		if ($$brhit_ref ne "-" && $$brhit_ref > 0) {
+			$block_hit = 1;
+			last;
+		}
+	}
+	foreach my $brhit_ref (@$brhits) {
+		if (!$block_hit) {
+			$$brhit_ref = "-";
+		} elsif ($$brhit_ref eq "-") {
+			$$brhit_ref = 0;
+		}
+	}
+}
+
+# Ensure coverage rate interdependencies are met
+sub sanitize_hits($$)
+{
+	my ($src, $hits) = @_;
+	my $files = $src->[0];
+
+	foreach my $hits (values(%{$hits})) {
+		my $brhits = $hits->[2];
+		my $i = 0;
+
+		foreach my $filename (sort(keys(%{$files}))) {
+			my $filesrc = $files->{$filename};
+			my $branches = $filesrc->[3];
+			my $lastblock;
+			my $lastline;
+			my @blist;
+
+			foreach my $brdata (@$branches) {
+				my ($brline, $block, $branch) = @$brdata;
+
+				if (!defined($lastblock) ||
+				    $block != $lastblock ||
+				    $brline != $lastline) {
+					sanitize_brhits(\@blist);
+					@blist = ();
+					$lastblock = $block;
+					$lastline = $brline;
+				}
+				push(@blist, \$brhits->[$i++]);
+			}
+			sanitize_brhits(\@blist);
+		}
+	}
+}
+
+# Generate random coverage data
+#
+# returns:	testname -> testhits
+# testhits:	[ lnhits, fnhits, brhits ]
+# lnhits:	[ ln1hit, ln2hit, ... ]
+# lnhit:	Number of times a line was hit by a specific test
+# fnhits:	[ fn1hit, fn2hit, ... ]
+# fnhit:	Number of times a function was hit by a specific test
+# brhits:	[ br1hit, br2hit, ... ]
+# brhit:	Number of times a branch was hit by a specific test
+sub gen_hits($$)
+{
+	my ($c, $src) = @_;
+	my (@lnhits, @fnhits, @brhits);
+	my ($files, $numlns, $numfns, $numbrs) = @$src;
+	my $testnames = get_list($c, "tests.names", "");
+	my %hits;
+
+	$testnames = [ "" ] if (!@$testnames);
+
+	foreach my $testname (@$testnames) {
+		my (@lnhits, @fnhits, @brhits);
+
+		for (my $i = 0; $i < $numlns; $i++) {
+			push(@lnhits, 1 + int(rand($MAX_TAKEN)));
+		}
+
+		for (my $i = 0; $i < $numfns; $i++) {
+			push(@fnhits, 1 + int(rand($MAX_TAKEN)));
+		}
+
+		for (my $i = 0; $i < $numbrs; $i++) {
+			push(@brhits, 1 + int(rand($MAX_TAKEN)));
+		}
+
+		$hits{$testname} = [ \@lnhits, \@fnhits, \@brhits ];
+	}
+
+	sanitize_hits($src, \%hits);
+
+	return \%hits;
+}
+
+# Return a hash containing RATE percent of indices [0..NUM-1].
+sub gen_filter($$)
+{
+	my ($num, $rate) = @_;
+	my @list = (0 .. ($num - 1));
+	my %hash;
+
+	reduce_list_per(\@list, $rate);
+	foreach my $i (@list) {
+		$hash{$i} = 1;
+	}
+
+	return \%hash;
+}
+
+# Zero all entries in LIST identified by the indices in FILTER.
+sub zero_by_filter($$)
+{
+	my ($list, $filter) = @_;
+
+	foreach my $i (keys(%{$filter})) {
+		$list->[$i] = 0;
+	}
+}
+
+# Add a random number of indices between [0..NUM-1] to FILTER.
+sub widen_filter($$)
+{
+	my ($filter, $num) = @_;
+	my @list;
+
+	for (my $i = 0; $i < $num; $i++) {
+		push(@list, $i) if (!exists($filter->{$i}));
+	}
+	reduce_list_per(\@list, int(rand(101)));
+
+	foreach my $i (@list) {
+		$filter->{$i} = 1;
+	}
+}
+
+# Zero coverage data in HITS until the combined coverage rates reach the
+# specified RATEs.
+sub reduce_hits($$$$$)
+{
+	my ($src, $hits, $lnrate, $fnrate, $brrate) = @_;
+	my ($files, $numlns, $numfns, $numbrs) = @$src;
+	my ($lnfilter, $fnfilter, $brfilter);
+
+	$lnfilter = gen_filter($numlns, 100 - $lnrate);
+	$fnfilter = gen_filter($numfns, 100 - $fnrate);
+	$brfilter = gen_filter($numbrs, 100 - $brrate);
+
+	foreach my $testhits (values(%{$hits})) {
+		my ($lnhits, $fnhits, $brhits) = @$testhits;
+
+		zero_by_filter($lnhits, $lnfilter);
+		zero_by_filter($fnhits, $fnfilter);
+		zero_by_filter($brhits, $brfilter);
+
+		# Provide some variation between tests
+		widen_filter($lnfilter, $numlns);
+		widen_filter($fnfilter, $numfns);
+		widen_filter($brfilter, $numbrs);
+	}
+
+	sanitize_hits($src, $hits);
+}
+
+sub zero_list($)
+{
+	my ($list) = @_;
+
+	foreach my $i (@$list) {
+		$i = 0;
+	}
+}
+
+# Zero all coverage in HITS.
+sub zero_hits($$)
+{
+	my ($src, $hits) = @_;
+
+	foreach my $testhits (values(%{$hits})) {
+		my ($lnhits, $fnhits, $brhits) = @$testhits;
+
+		zero_list($lnhits);
+		zero_list($fnhits);
+		zero_list($brhits);
+	}
+
+	sanitize_hits($src, $hits);
+}
+
+# Distribute items from LIST to A and B depending on whether the index for
+# an item is found in FILTER.
+sub split_by_filter($$$$)
+{
+	my ($list, $filter, $a, $b) = @_;
+
+	for (my $i = 0; $i < scalar(@$list); $i++) {
+		if (exists($filter->{$i})) {
+			push(@$a, $list->[$i]);
+			push(@$b, 0);
+		} else {
+			push(@$a, 0);
+			push(@$b, $list->[$i]);
+		}
+	}
+}
+
+sub split_hits($$$)
+{
+	my ($c, $src, $hits) = @_;
+	my ($files, $numlns, $numfns, $numbrs) = @$src;
+	my ($lnsplit, $fnsplit, $brsplit);
+	my (%a, %b);
+
+	$lnsplit = gen_filter($numlns, int(rand(101)));
+	$fnsplit = gen_filter($numfns, int(rand(101)));
+	$brsplit = gen_filter($numbrs, int(rand(101)));
+
+	foreach my $testname (keys(%{$hits})) {
+		my $testhits = $hits->{$testname};
+		my ($lnhits, $fnhits, $brhits) = @$testhits;
+		my (@lnhitsa, @fnhitsa, @brhitsa);
+		my (@lnhitsb, @fnhitsb, @brhitsb);
+
+		split_by_filter($lnhits, $lnsplit, \@lnhitsa, \@lnhitsb);
+		split_by_filter($fnhits, $fnsplit, \@fnhitsa, \@fnhitsb);
+		split_by_filter($brhits, $brsplit, \@brhitsa, \@brhitsb);
+
+		$a{$testname} = [ \@lnhitsa, \@fnhitsa, \@brhitsa ];
+		$b{$testname} = [ \@lnhitsb, \@fnhitsb, \@brhitsb ];
+	}
+
+	sanitize_hits($src, \%a);
+	sanitize_hits($src, \%b);
+
+	return (\%a, \%b);
+}
+
+sub plural($$$)
+{
+	my ($num, $sing, $plur) = @_;
+
+	return $num <= 1 ? $sing : $plur;
+}
+
+sub print_intro($)
+{
+	my ($c) = @_;
+	my $numtests = scalar(@{get_list($c, "tests.names")});
+	my $numfiles = get_int($c, "files.numfiles");
+
+	$numtests = 1 if ($numtests < 1);
+
+	print($BOLD."Creating coverage files ($numtests ".
+	      plural($numtests, "test", "tests").", $numfiles ".
+	      plural($numfiles, "source file", "source files").")\n".$RESET);
+}
+
+sub main()
+{
+	my $opt_help;
+	my $opt_output;
+	my $opt_configfile;
+	my $opt_seed = 0;
+	my $c;
+	my $src;
+	my $hits;
+	my $root;
+	my $enum;
+	my ($a, $b);
+
+	# Parse options
+	if (!GetOptions("output|o=s" => \$opt_output,
+			"seed=s" => \$opt_seed,
+			"help|h" => \$opt_help,
+	)) {
+		print(STDERR "Use $0 --help to get usage information\n");
+		exit(2);
+	}
+
+	if ($opt_help) {
+		usage();
+		exit(0);
+	}
+
+	$opt_configfile = shift(@ARGV);
+	if (!defined($opt_configfile)) {
+		print(STDERR "Please specify a config file\n");
+		exit(2);
+	}
+
+	if (defined($opt_output)) {
+		if (! -d $opt_output) {
+			mkdir($opt_output) or
+				die("$0: Could not create directory ".
+				    "$opt_output: $!\n");
+		}
+		$root = abs_path($opt_output)
+	} else {
+		$root = "/";
+	}
+
+	srand($opt_seed);
+
+	# Get config
+	$c = read_config($opt_configfile);
+	apply_config($c, \@ARGV) if (@ARGV);
+
+	print_intro($c);
+	# Show lines on STDOUT without newline
+	$| = 1;
+
+	# Create source tree
+	print("  Source tree ......... ");
+	$src = gen_src($c, $root);
+	# Write out source code if requested
+	write_src($src) if (defined($opt_output));
+	print("done (");
+	print($src->[1]." lines, ");
+	print($src->[2]." functions, ");
+	print($src->[3]." branches)\n");
+
+	# Write out full-coverage data files
+	print("  Full coverage ....... ");
+	$hits = gen_hits($c, $src);
+	write_info($c, "full.info", $src, $hits);
+	write_counts("full.counts", $hits);
+	print("done\n");
+
+	# Write out data files with target coverage rates
+	print("  Target coverage ..... ");
+	reduce_hits($src, $hits, get_int($c, "lines.covered"),
+				 get_int($c, "functions.covered"),
+				 get_int($c, "branches.covered"));
+	write_info($c, "target.info", $src, $hits);
+	write_counts("target.counts", $hits);
+	print("done\n");
+
+	# Write out partial data files
+	print("  Partial coverage .... ");
+	($a, $b) = split_hits($c, $src, $hits);
+	write_info($c, "part1.info", $src, $a);
+	write_counts("part1.counts", $a);
+	write_info($c, "part2.info", $src, $b);
+	write_counts("part2.counts", $b);
+	print("done\n");
+
+	# Write out zero-coverage data files
+	print("  Zero coverage ....... ");
+	zero_hits($src, $hits);
+	write_info($c, "zero.info", $src, $hits);
+	write_counts("zero.counts", $hits);
+	print("done\n");
+}
+
+main();
+exit(0);
diff --git a/externals/lcov/test/bin/norminfo b/externals/lcov/test/bin/norminfo
new file mode 100755
index 0000000000000000000000000000000000000000..9fe0ef2f00dfc7771e9eb636b931f3f41f1ffec4
--- /dev/null
+++ b/externals/lcov/test/bin/norminfo
@@ -0,0 +1,243 @@
+#!/usr/bin/env perl
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: norminfo <coverage-data-file> [<multiplier>]
+#
+# Normalize coverage data file (ensure stable order), perform some sanity
+# checks, and apply optional multiplier to execution counts.
+#
+
+use strict;
+use warnings;
+
+sub ferr($$$)
+{
+	my ($pos, $filename, $msg) = @_;
+
+	if (defined($pos)) {
+		$pos .= ":";
+	} else {
+		$pos = "";
+	}
+
+	die("$0:$filename:$pos $msg");
+}
+
+sub print_sorted($$$)
+{
+	my ($fd, $info, $multi) = @_;
+	my (%fn, %fns, %fnda, %brda, %da);
+	my ($fnf, $fnh, $brf, $brh, $lf, $lh);
+
+	while (my $line = <$fd>) {
+		$line =~ s/(^\s*|\s*$)//g;
+
+		if ($line =~ /^end_of_record$/) {
+			last;
+		} elsif ($line =~ /^FN:(\d+),(.*)$/) {
+			my ($lineno, $fnname) = ($1, $2);
+
+			if (exists($fn{$lineno})) {
+				ferr($., $info, "Duplicate FN: entry\n");
+			}
+			$fn{$lineno} = $fnname;
+			if (exists($fns{$fnname})) {
+				ferr($., $info, "Duplicate function name\n");
+			}
+			$fns{$fnname} = $lineno;
+		} elsif ($line =~ /^FNDA:(\d+),(.*)$/) {
+			my ($count, $fnname) = ($1, $2);
+
+			if (exists($fnda{$fnname})) {
+				ferr($., $info, "Duplicate FNDA: entry\n");
+			}
+			$fnda{$fnname} = int($count * $multi);
+		} elsif ($line =~ /^FNF:(\d+)$/) {
+			if (defined($fnf)) {
+				ferr($., $info, "Duplicate FNF: entry\n");
+			}
+			$fnf = $1;
+		} elsif ($line =~ /^FNH:(\d+)$/) {
+			if (defined($fnh)) {
+				ferr($., $info, "Duplicate FNH: entry\n");
+			}
+			$fnh = $1;
+		} elsif ($line =~ /^BRDA:(\d+),(\d+),(\d+),(\d+|-)$/) {
+			my ($lineno, $block, $branch, $count) = ($1, $2, $3, $4);
+
+			if (exists($brda{$lineno}->{$block}->{$branch})) {
+				ferr($., $info, "Duplicate BRDA: entry\n");
+			}
+			$count = int($count * $multi) if ($count ne "-");
+			$brda{$lineno}->{$block}->{$branch} = $count;
+
+		} elsif ($line =~ /^BRF:(\d+)$/) {
+			if (defined($brf)) {
+				ferr($., $info, "Duplicate BRF: entry\n");
+			}
+			$brf = $1;
+		} elsif ($line =~ /^BRH:(\d+)$/) {
+			if (defined($brh)) {
+				ferr($., $info, "Duplicate BRH: entry\n");
+			}
+			$brh = $1;
+		} elsif ($line =~ /^DA:(\d+),(\d+)$/) {
+			my ($lineno, $count) = ($1, $2);
+
+			if (exists($da{$lineno})) {
+				ferr($., $info, "Duplicate FNDA: entry\n");
+			}
+			$da{$lineno} = int($count * $multi);
+		} elsif ($line =~ /^LF:(\d+)$/) {
+			if (defined($lf)) {
+				ferr($., $info, "Duplicate LF: entry\n");
+			}
+			$lf = $1;
+		} elsif ($line =~ /^LH:(\d+)$/) {
+			if (defined($lh)) {
+				ferr($., $info, "Duplicate LH: entry\n");
+			}
+			$lh = $1;
+		} else {
+			ferr($., $info, "Unknown line: $line\n");
+		}
+	}
+
+	# FN:<line>,<fnname>
+	foreach my $lineno (sort({ $a <=> $b } keys(%fn))) {
+		my $fnname = $fn{$lineno};
+		print("FN:$lineno,$fnname\n");
+	}
+
+	# FNDA:<counts>,<fnname>
+	foreach my $fnname (keys(%fnda)) {
+		if (!exists($fns{$fnname})) {
+			ferr(undef, $info, "FNDA entry without FN: $fnname\n");
+		}
+	}
+	foreach my $fnname (sort({ $fns{$a} <=> $fns{$b} } keys(%fnda))) {
+		my $count = $fnda{$fnname};
+		print("FNDA:$count,$fnname\n");
+	}
+	# FNF:<counts>
+	print("FNF:$fnf\n") if (defined($fnf));
+	# FNH:<counts>
+	if (defined($fnh)) {
+		$fnh = 0 if ($multi == 0);
+		print("FNH:$fnh\n");
+	}
+	# BRDA:<line>,<block>,<branch>,<count>
+	foreach my $lineno (sort({ $a <=> $b } keys(%brda))) {
+		my $blocks = $brda{$lineno};
+
+		foreach my $block (sort({ $a <=> $b } keys(%{$blocks}))) {
+			my $branches = $blocks->{$block};
+
+			foreach my $branch (sort({ $a <=> $b }
+					    keys(%{$branches}))) {
+				my $count = $branches->{$branch};
+
+				$count = "-" if ($multi == 0);
+				print("BRDA:$lineno,$block,$branch,$count\n");
+			}
+		}
+
+	}
+	# BRF:<counts>
+	print("BRF:$brf\n") if (defined($brf));
+	# BRH:<counts>
+	if (defined($brh)) {
+		$brh = 0 if ($multi == 0);
+		print("BRH:$brh\n");
+	}
+	# DA:<line>,<counts>
+	foreach my $lineno (sort({ $a <=> $b } keys(%da))) {
+		my $count = $da{$lineno};
+
+		print("DA:$lineno,$count\n");
+	}
+	# LF:<counts>
+	print("LF:$lf\n") if (defined($lf));
+	# LH:<count>
+	if (defined($lh)) {
+		$lh = 0 if ($multi == 0);
+		print("LH:$lh\n");
+	}
+}
+
+sub main()
+{
+	my $infofile = $ARGV[0];
+	my $multi = $ARGV[1];
+	# info: testname -> files
+	# files: infofile -> data
+	# data: [ starting offset, starting line ]
+	my %info;
+	my $fd;
+	my $tn = "";
+	my %allfiles;
+
+	$multi = 1 if (!defined($multi));
+	if (!defined($infofile)) {
+		$infofile = "standard input";
+		warn("$0: Reading data from standard input\n");
+		open($fd, "<&STDIN") or
+			die("$0: Could not duplicated stdin: $!\n");
+	} else {
+		open($fd, "<", $infofile) or
+			die("$0: Could not open $infofile: $!\n");
+	}
+
+	# Register starting positions of data sets
+	while (my $line = <$fd>) {
+		if ($line =~ /^TN:(.*)$/) {
+			$tn = $1;
+		} elsif ($line =~ /^SF:(.*)$/) {
+			my $sf = $1;
+			my $pos = tell($fd);
+
+			die("$0: Could not get file position: $!\n")
+				if ($pos == -1);
+			if (exists($info{$tn}->{$sf})) {
+				ferr($., $infofile,
+				     "Duplicate entry for $tn:$sf\n");
+			}
+			$info{$tn}->{$sf} = [ $pos, $. ];
+			$allfiles{$sf} = 1;
+		}
+	}
+
+	# Print data sets in normalized order
+	foreach my $filename (sort(keys(%allfiles))) {
+		foreach my $testname (sort(keys(%info))) {
+			my $pos = $info{$testname}->{$filename};
+			my ($cpos, $lpos) = @$pos;
+
+			next if (!defined($pos));
+
+			if (seek($fd, $cpos, 0) != 1) {
+				die("$0: Could not seek in $infofile: $!\n");
+			}
+			printf("TN:$testname\n");
+			printf("SF:$filename\n");
+
+			$. = $lpos;
+			print_sorted($fd, $infofile, $multi);
+
+			printf("end_of_record\n");
+
+		}
+	}
+	foreach my $testname (sort(keys(%info))) {
+		my $files = $info{$testname};
+
+		foreach my $filename (sort(keys(%{$files}))) {
+		}
+	}
+
+	close($fd);
+}
+
+main();
+exit(0);
diff --git a/externals/lcov/test/bin/test_run b/externals/lcov/test/bin/test_run
new file mode 100755
index 0000000000000000000000000000000000000000..23e69d0f4e9534b424f9a2ecdf1ae712d1ff38df
--- /dev/null
+++ b/externals/lcov/test/bin/test_run
@@ -0,0 +1,99 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: test_run <testname> <cmdline>
+#
+# Announce a test case, run it, and record the resulting output in the
+# test log file. Must be run after testsuite_init.
+#
+
+TOPDIR=$(realpath $(dirname $0)/..) && source "$TOPDIR/bin/common"
+EXCERPTLEN=10
+TESTNAME="$1"
+shift
+
+TIME=$(which time 2>/dev/null)
+if [ ! -z "$TIME" ] ; then
+	TIME="$TIME -v -o $TIMEFILE"
+	if ! $TIME true 2>/dev/null ; then
+		TIME=""
+	fi
+fi
+
+t_announce "$TESTNAME"
+
+let POS=$(stat -c %s "$LOGFILE")+1
+
+t_detail "COMMAND" "\"$*\"" >>"$LOGFILE"
+t_detail "OUTPUT" "" >>"$LOGFILE"
+
+# Run command
+$TIME bash -c "$*" 2>&1 | t_indent >>"$LOGFILE"
+RC=$?
+
+# Evaluate output of time command
+ELAPSED=
+RESIDENT=
+SIGNAL=
+if [ ! -z "$TIME" ] ; then
+	while read LINE ; do
+		case "$LINE" in
+		"Command terminated by signal"*) SIGNAL=${LINE##* } ;;
+		"Elapsed"*) ELAPSED=$(elapsed_to_ms ${LINE##* }) ;;
+		"Maximum resident"*) RESIDENT=${LINE##* } ;;
+		"Exit status"*) RC=${LINE##* } ;;
+		esac
+	done < "$TIMEFILE"
+	rm -f "$TIMEFILE"
+fi
+
+t_detail "EXITCODE" "$RC" >>"$LOGFILE"
+
+# Show result
+if [ $RC -eq 0 -a -z "$SIGNAL" ] ; then
+	RESULT="pass"
+	t_pass "$TESTNAME"
+else
+	if [ -z "$SIGNAL" ] ; then
+		RESULT="fail"
+		t_fail "$TESTNAME"
+	else
+		RESULT="kill"
+		t_kill "$TESTNAME"
+	fi
+fi
+
+if [ ! -z "$SIGNAL" ] ; then
+	t_detail "SIGNAL" "$SIGNAL" >>"$LOGFILE"
+fi
+
+if [ ! -z "$ELAPSED" ] ; then
+	echo -n " (time $(($ELAPSED/1000)).$(($ELAPSED%1000/100))s, "
+	echo "elapsed $TESTNAME $ELAPSED" >> "$COUNTFILE"
+fi
+
+if [ ! -z "$RESIDENT" ] ; then
+	echo -n "mem $(($RESIDENT/1024)).$((($RESIDENT%1024)/100))MB)"
+	echo "resident $TESTNAME $RESIDENT" >> "$COUNTFILE"
+fi
+
+echo
+
+# Show log excerpt on failure or if requested
+if [ $RC -ne 0 -o "$V" == "1" ] ; then
+	LEN=$(tail -c "+$POS" "$LOGFILE" | wc -l)
+	if [ "$LEN" -gt "$EXCERPTLEN" -a "$V" != "1" ] ; then
+		tail -c "+$POS" "$LOGFILE" | head -n $EXCERPTLEN | t_indent
+		let LEN=$LEN-$EXCERPTLEN
+		echo "    ..."
+		echo "    Skipping $LEN more lines (see $LOGFILE)"
+	else
+		tail -c "+$POS" "$LOGFILE" | t_indent
+	fi
+fi
+
+# Log more details
+[ ! -z "$ELAPSED" ] && t_detail "TIME" "${ELAPSED}ms" >>"$LOGFILE"
+[ ! -z "$RESIDENT" ] && t_detail "MEM" "${RESIDENT}kB" >>"$LOGFILE"
+t_detail "RESULT" "$RESULT" >> "$LOGFILE"
diff --git a/externals/lcov/test/bin/test_skip b/externals/lcov/test/bin/test_skip
new file mode 100755
index 0000000000000000000000000000000000000000..202606f4f9acb5db95410ae06814d81952f14ad3
--- /dev/null
+++ b/externals/lcov/test/bin/test_skip
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: test_skip <testname> <reason>
+#
+# Announce and record that a single test case was skipped, including an
+# optional reason text. Must be run after testsuite_init.
+#
+
+TOPDIR=$(realpath $(dirname $0)/..) && source "$TOPDIR/bin/common"
+TESTNAME="$1"
+REASON="${*:2}" ; [ -z "$REASON" ] && REASON="<no reason given>"
+
+t_announce "$TESTNAME"
+t_skip "$TESTNAME"
+echo
+t_detail "REASON" "$REASON" >>"$LOGFILE"
+t_detail "REASON" "$REASON" | t_indent
diff --git a/externals/lcov/test/bin/testsuite_exit b/externals/lcov/test/bin/testsuite_exit
new file mode 100755
index 0000000000000000000000000000000000000000..6720df99f20bd924700a127cd903f2de1117ea36
--- /dev/null
+++ b/externals/lcov/test/bin/testsuite_exit
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: testsuite_exit
+#
+# Announce end of test suite and show aggregate results.
+#
+
+TOPDIR=$(realpath $(dirname $0)/..) && source "$TOPDIR/bin/common"
+
+echo "end_time $(date +%s.%N)" >>"$COUNTFILE"
+
+SUCCESS=0
+FAILED=0
+SKIPPED=0
+TOTAL_TIME=0
+TOTAL_MEM=0
+HAVE_EXT=0
+
+# Get results
+while read LINE ; do
+	set -- $LINE
+	case "$1" in
+	start_time)	START_TIME=$2 ;;
+	end_time)	END_TIME=$2 ;;
+	pass)		let SUCCESS=$SUCCESS+1 ;;
+	fail)		let FAILED=$FAILED+1 ;;
+	skip)		let SKIPPED=$SKIPPED+1 ;;
+	elapsed)	let TOTAL_TIME=$TOTAL_TIME+$3 ; HAVE_EXT=1 ;;
+	resident)	let TOTAL_MEM=$TOTAL_MEM+$3 ; HAVE_EXT=1 ;;
+	esac
+done < "$COUNTFILE"
+
+exec 3>&1
+exec >>"$LOGFILE" 2>&1
+
+t_marker
+t_detail "DATE" "$(t_timestamp)"
+
+let TOTAL=$SUCCESS+$SKIPPED+$FAILED
+t_detail "EXECUTED" "$TOTAL"
+t_detail "PASSED" "$SUCCESS"
+t_detail "FAILED" "$FAILED"
+t_detail "SKIPPED" "$SKIPPED"
+[ $HAVE_EXT -eq 1 ] && t_detail "TIME" "${TOTAL_TIME}ms"
+[ $HAVE_EXT -eq 1 ] && t_detail "MEM" "${TOTAL_MEM}kB"
+
+TOTAL_TIME=$(($TOTAL_TIME/1000)).$(($TOTAL_TIME%1000/100))
+TOTAL_MEM=$(($TOTAL_MEM/1024)).$((($TOTAL_MEM%1024)/100))
+TOTAL="$BOLD$TOTAL tests executed$RESET"
+PASS="$SUCCESS passed"
+FAIL="$FAILED failed"
+SKIP="$SKIPPED skipped"
+TIME="time ${TOTAL_TIME}s"
+MEM="mem ${TOTAL_MEM}MB"
+
+[ "$SUCCESS" -gt 0 ] && PASS="$GREEN$PASS$DEFAULT"
+[ "$FAILED"  -gt 0 ] && FAIL="$RED$FAIL$DEFAULT"
+[ "$SKIPPED" -gt 0 ] && SKIP="$BLUE$SKIP$DEFAULT"
+
+echo -en "$TOTAL, $PASS, $FAIL, $SKIP$RESET" >&3
+[ $HAVE_EXT -eq 1 ] && echo -n " ($TIME, $MEM)" >&3
+echo >&3
+echo "Result log stored in $LOGFILE" >&3
+
+if [ "$FAILED" -gt 0 ] ; then
+	exit 1
+fi
+
+exit 0
diff --git a/externals/lcov/test/bin/testsuite_init b/externals/lcov/test/bin/testsuite_init
new file mode 100755
index 0000000000000000000000000000000000000000..f901e35f13998caf371717a4946c53e1c49aafa2
--- /dev/null
+++ b/externals/lcov/test/bin/testsuite_init
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: testsuite_init
+#
+# Announce start of test suite and prepare log files.
+#
+
+TOPDIR=$(realpath $(dirname $0)/..) && source "$TOPDIR/bin/common"
+
+echo -e $BOLD"Starting tests"$RESET
+echo "start_time $(date +%s.%N)" >"$COUNTFILE"
+exec >"$LOGFILE" 2>&1
+
+t_detail "DATE" "$(t_timestamp)"
+
+t_detail "LCOV" ""
+lcov --version 2>&1 | t_indent
+
+t_detail "GCOV" ""
+gcov --version 2>&1 | t_indent
+
+t_detail "CPUINFO" ""
+t_indent < /proc/cpuinfo
+
+t_detail "MEMINFO" ""
+t_indent < /proc/meminfo
diff --git a/externals/lcov/test/common.mak b/externals/lcov/test/common.mak
new file mode 100644
index 0000000000000000000000000000000000000000..55f31eb99c32453e3a4325c3d7434bce4b0d3c1c
--- /dev/null
+++ b/externals/lcov/test/common.mak
@@ -0,0 +1,50 @@
+TOPDIR       := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
+TESTDIR      := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+PARENTDIR    := $(dir $(patsubst %/,%,$(TOPDIR)))
+RELDIR       := $(TESTDIR:$(PARENTDIR)%=%)
+ZEROINFO     := $(TOPDIR)zero.info
+ZEROCOUNTS   := $(TOPDIR)zero.counts
+FULLINFO     := $(TOPDIR)full.info
+FULLCOUNTS   := $(TOPDIR)full.counts
+TARGETINFO   := $(TOPDIR)target.info
+TARGETCOUNTS := $(TOPDIR)target.counts
+PART1INFO    := $(TOPDIR)part1.info
+PART1COUNTS  := $(TOPDIR)part1.counts
+PART2INFO    := $(TOPDIR)part2.info
+PART2COUNTS  := $(TOPDIR)part2.counts
+INFOFILES    := $(ZEROINFO) $(FULLINFO) $(TARGETINFO) $(PART1INFO) $(PART2INFO)
+COUNTFILES   := $(ZEROCOUNTS) $(FULLCOUNTS) $(TARGETCOUNTS) $(PART1COUNTS) \
+		$(PART2COUNTS)
+LCOVRC       := $(TOPDIR)lcovrc
+LCOVFLAGS    := --config-file $(LCOVRC)
+SIZE         := small
+CC           := gcc
+
+export LCOV := lcov $(LCOVFLAGS)
+export GENHTML := genhtml $(LCOVFLAGS)
+export PATH := $(TOPDIR)/../bin:$(TOPDIR)/bin:$(PATH)
+export LANG := C
+
+all: prepare init test exit
+
+init:
+	testsuite_init
+
+exit:
+	testsuite_exit
+
+prepare: $(INFOFILES) $(COUNTFILES)
+
+clean: clean_common
+
+clean_common:
+	echo "  CLEAN   $(patsubst %/,%,$(RELDIR))"
+
+$(INFOFILES) $(COUNTFILES):
+	cd $(TOPDIR) && mkinfo profiles/$(SIZE) -o src/
+
+ifneq ($(V),2)
+.SILENT:
+endif
+
+.PHONY: all init exit prepare clean clean_common
diff --git a/externals/lcov/test/genhtml_output/Makefile b/externals/lcov/test/genhtml_output/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..0fbd88267074b651e8bb94146136e8ed162dce13
--- /dev/null
+++ b/externals/lcov/test/genhtml_output/Makefile
@@ -0,0 +1,31 @@
+include ../common.mak
+
+GENHTML_TEST := ./genhtml_test
+
+TESTS := genhtml_output_zero genhtml_output_full genhtml_output_target \
+	 genhtml_output_part1 genhtml_output_part2 genhtml_output_combined
+
+test: $(TESTS)
+
+genhtml_output_zero:
+	@test_run genhtml_output_zero $(GENHTML) $(ZEROINFO) -o out_zero/
+
+genhtml_output_full:
+	@test_run genhtml_output_full $(GENHTML) $(FULLINFO) -o out_full/
+
+genhtml_output_target:
+	@test_run genhtml_output_target $(GENHTML) $(TARGETINFO) -o out_target/
+
+genhtml_output_part1:
+	@test_run genhtml_output_part1 $(GENHTML) $(PART1INFO) -o out_part1/
+
+genhtml_output_part2:
+	@test_run genhtml_output_part2 $(GENHTML) $(PART2INFO) -o out_part2/
+
+genhtml_output_combined: genhtml_output_target
+	@test_run genhtml_output_combined $(GENHTML_TEST) $(TARGETINFO) $(PART1INFO) $(PART2INFO)
+
+clean:
+	rm -rf out_*/
+
+.PHONY: test $(TESTS) clean
diff --git a/externals/lcov/test/genhtml_output/genhtml_test b/externals/lcov/test/genhtml_output/genhtml_test
new file mode 100755
index 0000000000000000000000000000000000000000..0b0f834918e5eb92076d98a592aaea028aa0ab86
--- /dev/null
+++ b/externals/lcov/test/genhtml_output/genhtml_test
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: genhtml_test <ref-file> <file1> [<file2>...]
+#
+# Compare genhtml output of a reference coverage data file with that of
+# a combination of multiple files.
+#
+
+function die()
+{
+	echo "Error: $@" >&2
+	exit 1
+}
+
+GENHTMLFLAGS="-t title"
+REFFILE=$1
+shift
+
+if [ -z "$REFFILE" -o -z "$*" ] ; then
+	echo "Usage: $0 <ref-file> <file1> [<file2>...]" >&2
+	exit 2
+fi
+
+OUTREF="out_$(basename $REFFILE .info)"
+OUTCOMBINED="out_combined"
+
+$GENHTML $GENHTMLFLAGS "$REFFILE" -o "$OUTREF" || \
+	die "Could not generate HTML for reference file"
+
+$GENHTML $GENHTMLFLAGS "$@" -o "$OUTCOMBINED" || \
+	die "Could not generate HTML for combined files"
+
+diff -ur "$OUTREF" "$OUTCOMBINED" -I "headerValue" || \
+	die "Mismatch in generated output"
diff --git a/externals/lcov/test/lcov_add_files/Makefile b/externals/lcov/test/lcov_add_files/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..87937a155845f676e6352fe5c161c5f4cb0d31ae
--- /dev/null
+++ b/externals/lcov/test/lcov_add_files/Makefile
@@ -0,0 +1,47 @@
+include ../common.mak
+
+ADDTEST := ./add_test
+
+TESTS := lcov_add_zero lcov_add_zero2 lcov_add_full lcov_add_full2 \
+	 lcov_add_part lcov_add_part2 lcov_add_concatenated4
+
+
+test: $(TESTS)
+
+lcov_add_zero:
+	# Add single zero coverage file - output should be same as input
+	test_run lcov_add_zero $(ADDTEST) 1 "$(ZEROINFO)" "$(ZEROINFO)"
+
+lcov_add_zero2:
+	# Add two zero coverage files - output should be same as input
+	test_run lcov_add_zero2 $(ADDTEST) 1 "$(ZEROINFO)" "$(ZEROINFO)" "$(ZEROINFO)"
+
+lcov_add_full:
+	# Add single 100% coverage file - output should be same as input
+	test_run lcov_add_full $(ADDTEST) 1 "$(FULLINFO)" "$(FULLINFO)"
+
+lcov_add_full2:
+	# Add two 100% coverage file and reduce counts to 1/2 - output should
+	# be same as input
+	test_run lcov_add_full2 $(ADDTEST) 0.5 "$(FULLINFO)" "$(FULLINFO)" "$(FULLINFO)"
+
+lcov_add_part:
+	# Add single coverage file with random coverage rate - output should
+	# be same as input
+	test_run lcov_add_part $(ADDTEST) 1 "$(PART1INFO)" "$(PART1INFO)"
+
+lcov_add_part2:
+	# Add two coverage files that were split from target file - output
+	# should be same as target file
+	test_run lcov_add_part2 $(ADDTEST) 1 "$(TARGETINFO)" "$(PART1INFO)" "$(PART2INFO)"
+
+lcov_add_concatenated4:
+	# Add coverage file that consists of 4 concatenation of target files 
+	# and reduce counts to 1/4 - output should be the same as input
+	cat $(TARGETINFO) $(TARGETINFO) $(TARGETINFO) $(TARGETINFO) >concatenated.info
+	test_run lcov_add_concatenated4 $(ADDTEST) 0.25 $(TARGETINFO) concatenated.info
+
+clean:
+	rm -f *.info
+
+.PHONY: test $(TESTS) clean
diff --git a/externals/lcov/test/lcov_add_files/add_test b/externals/lcov/test/lcov_add_files/add_test
new file mode 100755
index 0000000000000000000000000000000000000000..4ff5ffeb6c74270e2acdceceb93556334281a014
--- /dev/null
+++ b/externals/lcov/test/lcov_add_files/add_test
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: add_test <multiplier> <reference_file> <add_file> [<add_file>...]
+#
+# Add multiple coverage data files, normalize the output and multiply counts
+# with multiplier. Compare against reference file. Report deviations.
+#
+
+MULTI=$1
+REFFILE=$2
+shift 2
+
+ADD=
+for INFO in $* ; do
+	ADD="$ADD -a $INFO"
+done
+
+if [ -z "$MULTI" -o -z "$REFFILE" -o -z "$ADD" ] ; then
+	echo "Usage: $0 <multiplier> <reference_file> <add_file> [<add_file>...]" >&2
+	exit 1
+fi
+
+OUTFILE="add_"$(basename "$REFFILE")
+SORTFILE="norm_$OUTFILE"
+
+set -x
+
+echo "Adding files..."
+if ! $LCOV $ADD -o "$OUTFILE" ; then
+	echo "Error: lcov returned with non-zero exit code $?" >&2
+	exit 1
+fi
+
+echo "Normalizing result..."
+if ! norminfo "$OUTFILE" "$MULTI" > "$SORTFILE" ; then
+	echo "Error: Normalization of lcov result file failed" >&2
+	exit 1
+fi
+
+echo "Comparing with reference..."
+if ! diff -u "$REFFILE" "$SORTFILE" ; then
+	echo "Error: Result of combination differs from reference file" >&2
+	exit 1
+fi
diff --git a/externals/lcov/test/lcov_diff/Makefile b/externals/lcov/test/lcov_diff/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d2d4dd6621bd5b0c1b858ce811450385625fa8b5
--- /dev/null
+++ b/externals/lcov/test/lcov_diff/Makefile
@@ -0,0 +1,9 @@
+include ../common.mak
+
+test:
+	test_run lcov_diff_apply ./diff_test
+
+clean:
+	make -C old clean
+	make -C new clean
+	rm -f *.info diff
diff --git a/externals/lcov/test/lcov_diff/diff_test b/externals/lcov/test/lcov_diff/diff_test
new file mode 100755
index 0000000000000000000000000000000000000000..e0f8c0b3081845a795960514b5f2b33a443bc4b9
--- /dev/null
+++ b/externals/lcov/test/lcov_diff/diff_test
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: diff_test
+#
+# Check lcov's diff function:
+# - Compile two slightly different test programs
+# - Run the programs and collect coverage data
+# - Generate a patch containing the difference between the source code
+# - Apply the patch to the coverage data
+# - Compare the resulting patched coverage data file with the data from the
+#   patched source file
+#
+
+function die()
+{
+	echo "Error: $@" >&2
+	exit 1
+}
+
+make -C old || die "Failed to compile old source"
+make -C new || die "Failed to compile new source"
+diff -u $PWD/old/prog.c $PWD/new/prog.c > diff
+
+$LCOV --diff old/prog.info diff --convert-filenames -o patched.info -t bla || \
+	die "Failed to apply patch to coverage data file"
+norminfo new/prog.info > new_normalized.info
+norminfo patched.info > patched_normalized.info
+sed -i -e 's/^TN:.*$/TN:/' patched_normalized.info
+
+diff -u patched_normalized.info new_normalized.info || \
+	die "Mismatch in patched coverage data file"
+
+echo "Patched coverage data file matches expected file"
diff --git a/externals/lcov/test/lcov_diff/new/Makefile b/externals/lcov/test/lcov_diff/new/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..51005c71dd74b21133d48f5c64ee1998e2473d67
--- /dev/null
+++ b/externals/lcov/test/lcov_diff/new/Makefile
@@ -0,0 +1,17 @@
+prog.info:
+
+include ../../common.mak
+
+prog.info: prog.gcda
+	$(LCOV) -c -d . -o prog.info
+
+prog.gcda: prog
+	./prog || true
+
+prog: prog.c
+	$(CC) prog.c -o prog --coverage
+
+clean:
+	rm -f prog prog.gcda prog.gcno prog.info
+
+.PHONY: all clean
diff --git a/externals/lcov/test/lcov_diff/new/prog.c b/externals/lcov/test/lcov_diff/new/prog.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f4607cc4fd8d6b537f19eac54080e3a09f506de
--- /dev/null
+++ b/externals/lcov/test/lcov_diff/new/prog.c
@@ -0,0 +1,41 @@
+
+
+
+int fn(int x)
+{
+	switch (x) {
+	case -1: return 0;
+
+
+	case 0:  return 2;
+	case 2:  return 3;
+
+
+	case 12: return 7;
+	default: return 255;
+	}
+
+
+
+}
+
+int fn2()
+{
+
+
+	return 7;
+}
+
+
+
+int main(int argc, char *argv[])
+{
+
+
+	if (argc > 1)
+		return fn(argc);
+
+	return fn2();
+
+
+}
diff --git a/externals/lcov/test/lcov_diff/old/Makefile b/externals/lcov/test/lcov_diff/old/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..51005c71dd74b21133d48f5c64ee1998e2473d67
--- /dev/null
+++ b/externals/lcov/test/lcov_diff/old/Makefile
@@ -0,0 +1,17 @@
+prog.info:
+
+include ../../common.mak
+
+prog.info: prog.gcda
+	$(LCOV) -c -d . -o prog.info
+
+prog.gcda: prog
+	./prog || true
+
+prog: prog.c
+	$(CC) prog.c -o prog --coverage
+
+clean:
+	rm -f prog prog.gcda prog.gcno prog.info
+
+.PHONY: all clean
diff --git a/externals/lcov/test/lcov_diff/old/prog.c b/externals/lcov/test/lcov_diff/old/prog.c
new file mode 100644
index 0000000000000000000000000000000000000000..a4eda2555769efe16e0d7bba542fc3dfb31d28b5
--- /dev/null
+++ b/externals/lcov/test/lcov_diff/old/prog.c
@@ -0,0 +1,22 @@
+int fn(int x)
+{
+	switch (x) {
+	case -1: return 0;
+	case 0:  return 2;
+	case 2:  return 3;
+	case 12: return 7;
+	default: return 255;
+	}
+}
+
+int fn2()
+{
+	return 7;
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc > 1)
+		return fn(argc);
+	return fn2();
+}
diff --git a/externals/lcov/test/lcov_misc/Makefile b/externals/lcov/test/lcov_misc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d3bcc4ab28582cd7a34a0fdc1a54aceaecf08ca0
--- /dev/null
+++ b/externals/lcov/test/lcov_misc/Makefile
@@ -0,0 +1,5 @@
+include ../common.mak
+
+test:
+	@test_run lcov_version lcov --version
+	@test_run lcov_help lcov --help
diff --git a/externals/lcov/test/lcov_summary/Makefile b/externals/lcov/test/lcov_summary/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f48d0bc7667d759e2cf04597095ad012626ff647
--- /dev/null
+++ b/externals/lcov/test/lcov_summary/Makefile
@@ -0,0 +1,41 @@
+include ../common.mak
+
+CHECK := ./check_counts
+TESTS := lcov_summary_zero lcov_summary_full lcov_summary_target \
+	 lcov_summary_part1 lcov_summary_part2 lcov_summary_concatenated \
+	 lcov_summary_concatenated2
+
+test: $(TESTS)
+
+lcov_summary_zero:
+	# Compare output of lcov --summary with generated counts
+	test_run lcov_summary_zero $(CHECK) $(ZEROCOUNTS) $(ZEROINFO)
+lcov_summary_full:
+	# Compare output of lcov --summary with generated counts
+	test_run lcov_summary_full $(CHECK) $(FULLCOUNTS) $(FULLINFO)
+lcov_summary_target:
+	# Compare output of lcov --summary with generated counts
+	test_run lcov_summary_target $(CHECK) $(TARGETCOUNTS) $(TARGETINFO)
+lcov_summary_part1:
+	# Compare output of lcov --summary with generated counts
+	test_run lcov_summary_part1 $(CHECK) $(PART1COUNTS) $(PART1INFO)
+lcov_summary_part2:
+	# Compare output of lcov --summary with generated counts
+	test_run lcov_summary_part2 $(CHECK) $(PART2COUNTS) $(PART2INFO)
+lcov_summary_concatenated:
+	# Compare output of lcov --summary with generated counts for a
+	# concatenated coverage data file
+	cat $(TARGETINFO) $(TARGETINFO) > concatenated.info
+	test_run lcov_summary_concatenated $(CHECK) $(TARGETCOUNTS) concatenated.info
+lcov_summary_concatenated2:
+	# Compare output of lcov --summary with generated counts for a
+	# concatenated coverage data file (part1+part2=target)
+	cat $(PART1INFO) $(PART2INFO) > concatenated2.info
+	test_run lcov_summary_concatenated2 $(CHECK) $(TARGETCOUNTS) concatenated2.info
+
+
+
+clean:
+	rm -f *.info
+
+.PHONY: test $(TESTS) clean
diff --git a/externals/lcov/test/lcov_summary/check_counts b/externals/lcov/test/lcov_summary/check_counts
new file mode 100755
index 0000000000000000000000000000000000000000..32d454230ccc4682f532524bce4638e9dfe0be49
--- /dev/null
+++ b/externals/lcov/test/lcov_summary/check_counts
@@ -0,0 +1,70 @@
+#!/usr/bin/env perl
+#
+# Copyright IBM Corp. 2017
+#
+# Usage: check_counts <counts_file> <coverage_data_file>
+#
+# Compare the output of "lcov --summary" for <coverage_data_file> with the
+# coverage data counts specified in <counts_file>. This file has the following
+# format (all in a single line):
+#
+#   lnhit lnfound fnhit fnfound brhit brfound2
+#
+
+use strict;
+use warnings;
+
+sub do_cmp($$$)
+{
+	my ($title, $a, $b) = @_;
+
+	if ($a == $b) {
+		print("$title: $a == $b\n");
+		return 0;
+	} else {
+		print("$title: $a != $b => mismatch!\n");
+		return 1;
+	}
+}
+
+my $lcov = $ENV{"LCOV"};
+my ($counts, $info) = @ARGV;
+my $fd;
+my $cmdline;
+my ($lnhit, $lnfound, $fnhit, $fnfound, $brhit, $brfound) = (0, 0, 0, 0, 0, 0);
+my ($lnhit2, $lnfound2, $fnhit2, $fnfound2, $brhit2, $brfound2);
+my $rc = 0;
+
+die("$0: LCOV environment variable not defined\n") if (!defined($lcov));
+if (!defined($counts) || !defined($info)) {
+	die("Usage: $0 <counts_file> <coverage_data_file>\n");
+}
+
+$cmdline = "$lcov --summary $info";
+open($fd, "-|", $cmdline) or die("$0: Could not run $cmdline: $!\n");
+while (<$fd>) {
+	($lnhit, $lnfound) = ($1, $2) if (/(\d+) of (\d+) lines/);
+	($fnhit, $fnfound) = ($1, $2) if (/(\d+) of (\d+) functions/);
+	($brhit, $brfound) = ($1, $2) if (/(\d+) of (\d+) branches/);
+}
+close($fd);
+
+die("$0: Non-zero result code ($?) of command: $cmdline\n") if ($? != 0);
+
+open($fd, "<", $counts) or die("$0: Could not open $counts: $!\n");
+if (<$fd> !~ /^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
+	die("$0: Invalid count file: $counts\n");
+}
+($lnhit2, $lnfound2, $fnhit2, $fnfound2, $brhit2, $brfound2) =
+	($1, $2, $3, $4, $5, $6);
+close($fd);
+
+print("Comparing --summary output for $info and $counts:\n");
+$rc |= do_cmp("line hit", $lnhit, $lnhit2);
+$rc |= do_cmp("line found", $lnfound, $lnfound2);
+$rc |= do_cmp("functions hit", $fnhit, $fnhit2);
+$rc |= do_cmp("functions found", $fnfound, $fnfound2);
+$rc |= do_cmp("branches hit", $brhit, $brhit2);
+$rc |= do_cmp("branches found", $brfound, $brfound2);
+
+exit($rc);
diff --git a/externals/lcov/test/lcovrc b/externals/lcov/test/lcovrc
new file mode 100644
index 0000000000000000000000000000000000000000..5005f637d5f7f2d434b54ab88067152fb12f208f
--- /dev/null
+++ b/externals/lcov/test/lcovrc
@@ -0,0 +1,4 @@
+# lcovrc file used during tests
+
+lcov_function_coverage = 1
+lcov_branch_coverage = 1
diff --git a/externals/lcov/test/profiles/large b/externals/lcov/test/profiles/large
new file mode 100644
index 0000000000000000000000000000000000000000..31788b040933f33b044a6f7591a83fa310d910bb
--- /dev/null
+++ b/externals/lcov/test/profiles/large
@@ -0,0 +1,51 @@
+# Profile of a large source code project. Use with mkinfo to generate fake test
+# source code and coverage data.
+
+[tests]
+# List of test names
+names	= test1 test2
+
+[files]
+# Create this many files
+numfiles = 500
+# Generate paths from these components (top/sub/subsub/prefix_suffix.ext)
+top	= lib tools test bin img scripts
+sub	= build debug release include target sys config
+subsub	= work www utils gui info log basic
+prefix	= main misc report tune mem list 
+suffix	= a b c top work proto final fast
+ext	= .c .h
+
+[lines]
+# Generate line coverage data
+enabled	= 1
+# Line coverage rate
+covered	= 80
+# Percentage of lines covered
+instrumented = 80
+# Maximum number of lines per file
+maxlines = 2000
+
+[functions]
+# Generate function coverage data
+enabled	= 1
+# Function coverage rate
+covered	= 60
+# Percent of instrumented lines containing function definitions
+perinstrumented = 10
+# Generate function names from these components (verb_adj_noun)
+verb	= get set find read write stat add sub combine
+adj	= first last best min max avg
+noun	= bit byte file str num obj data
+
+[branches]
+# Generate branch coverage data
+enabled	= 1
+# Branch coverage rate
+covered = 20
+# Percent of instrumented lines containing branches
+perinstrumented = 5
+# List of blocks to use
+blocks	= 0 4294967295
+# Distribution of number of branches per block (num:probability)
+branchdist = 2:50 3:25 5:20 100:5
diff --git a/externals/lcov/test/profiles/medium b/externals/lcov/test/profiles/medium
new file mode 100644
index 0000000000000000000000000000000000000000..56598e868271a98498b88f7361f9b5b5a109f4d4
--- /dev/null
+++ b/externals/lcov/test/profiles/medium
@@ -0,0 +1,51 @@
+# Profile of a medium-sized source code project. Use with mkinfo to generate
+# fake test source code and coverage data.
+
+[tests]
+# List of test names
+names	= test1 test2 test3
+
+[files]
+# Create this many files
+numfiles = 50
+# Generate paths from these components (top/sub/subsub/prefix_suffix.ext)
+top	= lib tools test bin img scripts
+sub	= build debug release include target sys config
+subsub	= work www utils gui info log basic
+prefix	= main misc report tune mem list 
+suffix	= a b c top work proto final fast
+ext	= .c .h
+
+[lines]
+# Generate line coverage data
+enabled	= 1
+# Line coverage rate
+covered	= 80
+# Percentage of lines covered
+instrumented = 50
+# Maximum number of lines per file
+maxlines = 1000
+
+[functions]
+# Generate function coverage data
+enabled	= 1
+# Function coverage rate
+covered	= 60
+# Percent of instrumented lines containing function definitions
+perinstrumented = 5
+# Generate function names from these components (verb_adj_noun)
+verb	= get set find read write stat add sub combine
+adj	= first last best min max avg
+noun	= bit byte file str num obj data
+
+[branches]
+# Generate branch coverage data
+enabled	= 1
+# Branch coverage rate
+covered = 20
+# Percent of instrumented lines containing branches
+perinstrumented = 50
+# List of blocks to use
+blocks	= 0 4294967295
+# Distribution of number of branches per block (num:probability)
+branchdist = 2:50 3:50
diff --git a/externals/lcov/test/profiles/small b/externals/lcov/test/profiles/small
new file mode 100644
index 0000000000000000000000000000000000000000..388d2a3bb55926031ed85164fa2250bd096191c3
--- /dev/null
+++ b/externals/lcov/test/profiles/small
@@ -0,0 +1,51 @@
+# Profile of a small source code project. Use with mkinfo to generate fake test
+# source code and coverage data.
+
+[tests]
+# List of test names
+names	= test1 test2
+
+[files]
+# Create this many files
+numfiles = 5
+# Generate paths from these components (top/sub/subsub/prefix_suffix.ext)
+top	= lib tools test bin img scripts
+sub	= build debug release include target sys config
+subsub	= work www utils gui info log basic
+prefix	= main misc report tune mem list 
+suffix	= a b c top work proto final fast
+ext	= .c .h
+
+[lines]
+# Generate line coverage data
+enabled	= 1
+# Line coverage rate
+covered	= 80
+# Percentage of lines covered
+instrumented = 50
+# Maximum number of lines per file
+maxlines = 500
+
+[functions]
+# Generate function coverage data
+enabled	= 1
+# Function coverage rate
+covered	= 60
+# Percent of instrumented lines containing function definitions
+perinstrumented = 5
+# Generate function names from these components (verb_adj_noun)
+verb	= get set find read write stat add sub combine
+adj	= first last best min max avg
+noun	= bit byte file str num obj data
+
+[branches]
+# Generate branch coverage data
+enabled	= 1
+# Branch coverage rate
+covered = 20
+# Percent of instrumented lines containing branches
+perinstrumented = 50
+# List of blocks to use
+blocks	= 0 4294967295
+# Distribution of number of branches per block (num:probability)
+branchdist = 2:50 3:45 50:5
diff --git a/externals/spdlog b/externals/spdlog
new file mode 160000
index 0000000000000000000000000000000000000000..cbe9448650176797739dbab13961ef4c07f4290f
--- /dev/null
+++ b/externals/spdlog
@@ -0,0 +1 @@
+Subproject commit cbe9448650176797739dbab13961ef4c07f4290f
diff --git a/dependencies/CMakeLists.txt b/modules/CMakeLists.txt
similarity index 100%
rename from dependencies/CMakeLists.txt
rename to modules/CMakeLists.txt
diff --git a/modules/conex b/modules/conex
new file mode 160000
index 0000000000000000000000000000000000000000..c17fc68bd35612e1b610ce2b43e84e91577b8a86
--- /dev/null
+++ b/modules/conex
@@ -0,0 +1 @@
+Subproject commit c17fc68bd35612e1b610ce2b43e84e91577b8a86
diff --git a/modules/data b/modules/data
new file mode 160000
index 0000000000000000000000000000000000000000..1a5a145b10ceb475eba05e5cc29a4dc9f543a032
--- /dev/null
+++ b/modules/data
@@ -0,0 +1 @@
+Subproject commit 1a5a145b10ceb475eba05e5cc29a4dc9f543a032
diff --git a/modules/proposal b/modules/proposal
new file mode 160000
index 0000000000000000000000000000000000000000..6d6ca1f62430df84918d770fa9b9eb30347e0dd9
--- /dev/null
+++ b/modules/proposal
@@ -0,0 +1 @@
+Subproject commit 6d6ca1f62430df84918d770fa9b9eb30347e0dd9
diff --git a/dependencies/pythia/CMakeLists.txt b/modules/pythia/CMakeLists.txt
similarity index 96%
rename from dependencies/pythia/CMakeLists.txt
rename to modules/pythia/CMakeLists.txt
index 701303282c3de35ae9515cdb3fb26dd4b333516f..6aceb1ad005e8c20ffef524fe461909363041c7f 100644
--- a/dependencies/pythia/CMakeLists.txt
+++ b/modules/pythia/CMakeLists.txt
@@ -33,7 +33,7 @@ if ("x_${USE_PYTHIA8_C8}" STREQUAL "x_SYSTEM")
 else ()
 
   set (_C8_Pythia8_VERSION "8235")
-  message (STATUS "Building ThirdParty/pythia8 using pythia${_C8_Pythia8_VERSION}-stripped.tar.bz2")
+  message (STATUS "Building modules/pythia8 using pythia${_C8_Pythia8_VERSION}-stripped.tar.bz2")
   message (STATUS "This will take a bit.....")
   ExternalProject_Add (pythia8
     URL ${CMAKE_CURRENT_SOURCE_DIR}/pythia${_C8_Pythia8_VERSION}-stripped.tar.bz2
diff --git a/dependencies/pythia/pythia8235-stripped.tar.bz2 b/modules/pythia/pythia8235-stripped.tar.bz2
similarity index 100%
rename from dependencies/pythia/pythia8235-stripped.tar.bz2
rename to modules/pythia/pythia8235-stripped.tar.bz2
diff --git a/dependencies/qgsjetII/CMakeLists.txt b/modules/qgsjetII/CMakeLists.txt
similarity index 62%
rename from dependencies/qgsjetII/CMakeLists.txt
rename to modules/qgsjetII/CMakeLists.txt
index e78300fe6ab67124a8817f06fd2572b7279bc876..2ddb6b023f7e4d0320a7f827027c165d504b6a48 100644
--- a/dependencies/qgsjetII/CMakeLists.txt
+++ b/modules/qgsjetII/CMakeLists.txt
@@ -1,21 +1,21 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required (VERSION 3.1)
 
-project(libQGSJetII)
+project (libQGSJetII)
 
 set (
   MODEL_SOURCES
   qgsjet-II-04-mod1.f
+  qgsjet-II-04.cpp
   )
 
 set (
   MODEL_HEADERS
-  qgsjet-II-04.h
+  qgsjet-II-04.hpp
   )
 
-
-enable_language(Fortran)
+enable_language (Fortran)
 add_library (QGSJetII SHARED ${MODEL_SOURCES})
-set_property(TARGET QGSJetII PROPERTY POSITION_INDEPENDENT_CODE 1)
+set_target_properties (QGSJetII PROPERTIES POSITION_INDEPENDENT_CODE 1)
 
 target_include_directories (
   QGSJetII
@@ -23,10 +23,10 @@ target_include_directories (
   $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
   $<INSTALL_INTERFACE:include/include>
   )
-
+target_link_libraries (QGSJetII CorsikaData)
 
 add_library (QGSJetII_static STATIC ${MODEL_SOURCES})
-set_property(TARGET QGSJetII_static PROPERTY POSITION_INDEPENDENT_CODE 1)
+set_target_properties (QGSJetII_static PROPERTIES POSITION_INDEPENDENT_CODE 1)
 
 target_include_directories (
   QGSJetII_static
@@ -34,6 +34,7 @@ target_include_directories (
   $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
   $<INSTALL_INTERFACE:include/include>
   )
+target_link_libraries (QGSJetII_static CorsikaData)
 
 
 # add qgsjetII to corsika8 build
diff --git a/dependencies/qgsjetII/README.md b/modules/qgsjetII/README.md
similarity index 100%
rename from dependencies/qgsjetII/README.md
rename to modules/qgsjetII/README.md
diff --git a/dependencies/qgsjetII/qgsjet-II-04-mod1.f b/modules/qgsjetII/qgsjet-II-04-mod1.f
similarity index 100%
rename from dependencies/qgsjetII/qgsjet-II-04-mod1.f
rename to modules/qgsjetII/qgsjet-II-04-mod1.f
diff --git a/dependencies/qgsjetII/qgsjet-II-04-org.f b/modules/qgsjetII/qgsjet-II-04-org.f
similarity index 100%
rename from dependencies/qgsjetII/qgsjet-II-04-org.f
rename to modules/qgsjetII/qgsjet-II-04-org.f
diff --git a/modules/qgsjetII/qgsjet-II-04.cpp b/modules/qgsjetII/qgsjet-II-04.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eea2724a88c07f1b028aba0703173a1ebc1f0504
--- /dev/null
+++ b/modules/qgsjetII/qgsjet-II-04.cpp
@@ -0,0 +1,23 @@
+#include <qgsjet-II-04.hpp>
+
+#include <iostream>
+
+datadir::datadir(const std::string& dir) {
+  if (dir.length() > 130) {
+    std::cerr << "QGSJetII error, will cut datadir \"" << dir
+              << "\" to 130 characters: " << std::endl;
+  }
+  int i = 0;
+  for (i = 0; i < std::min(130, int(dir.length())); ++i) data[i] = dir[i];
+  data[i + 0] = ' ';
+  data[i + 1] = '\0';
+}
+
+
+/**
+   @function qgran
+
+   link to random number generation
+ */
+double qgran_(int&) { return qgsjetII::rndm_interface(); } 
+
diff --git a/dependencies/qgsjetII/qgsjet-II-04.hpp b/modules/qgsjetII/qgsjet-II-04.hpp
similarity index 89%
rename from dependencies/qgsjetII/qgsjet-II-04.hpp
rename to modules/qgsjetII/qgsjet-II-04.hpp
index f9f75d826371873fc9985fb05478c48c81ab17dc..7b41f01ed1413874a27a36b1f8a0b41f4ba2f5f2 100644
--- a/dependencies/qgsjetII/qgsjet-II-04.hpp
+++ b/modules/qgsjetII/qgsjet-II-04.hpp
@@ -10,6 +10,19 @@
 
 #include <string>
 
+namespace qgsjetII {
+
+  /**
+   * \function qgsjetII::rndm_interface
+   *
+   * this is the random number hook to external packages.
+   *
+   * CORSIKA8, for example, has to provide an implementation of this.
+   **/
+  extern double rndm_interface();
+
+} // namespace sibyll
+
 //----------------------------------------------
 //  C++ interface for the QGSJetII event generator
 //----------------------------------------------
diff --git a/dependencies/sibyll/CMakeLists.txt b/modules/sibyll/CMakeLists.txt
similarity index 92%
rename from dependencies/sibyll/CMakeLists.txt
rename to modules/sibyll/CMakeLists.txt
index 86c9f9791a679644212deb69cb58cb9db46613ac..361fd8b56af9b970fb8627b14a03b966cfcf4273 100644
--- a/dependencies/sibyll/CMakeLists.txt
+++ b/modules/sibyll/CMakeLists.txt
@@ -1,6 +1,3 @@
-#cmake_minimum_required(VERSION 3.1)
-#project(Sibyll)
-
 set (
   MODEL_SOURCES
   sibyll2.3d.cpp
@@ -8,7 +5,6 @@ set (
   nuclib.f
   signuc.f
   gasdev.f
-  #rndm_dbl.f
   )
 
 set (
diff --git a/dependencies/sibyll/gasdev.f b/modules/sibyll/gasdev.f
similarity index 100%
rename from dependencies/sibyll/gasdev.f
rename to modules/sibyll/gasdev.f
diff --git a/dependencies/sibyll/nuclib.f b/modules/sibyll/nuclib.f
similarity index 100%
rename from dependencies/sibyll/nuclib.f
rename to modules/sibyll/nuclib.f
diff --git a/dependencies/sibyll/nuclib.hpp b/modules/sibyll/nuclib.hpp
similarity index 100%
rename from dependencies/sibyll/nuclib.hpp
rename to modules/sibyll/nuclib.hpp
diff --git a/dependencies/sibyll/sibyll2.3d.cpp b/modules/sibyll/sibyll2.3d.cpp
similarity index 100%
rename from dependencies/sibyll/sibyll2.3d.cpp
rename to modules/sibyll/sibyll2.3d.cpp
diff --git a/dependencies/sibyll/sibyll2.3d.f b/modules/sibyll/sibyll2.3d.f
similarity index 100%
rename from dependencies/sibyll/sibyll2.3d.f
rename to modules/sibyll/sibyll2.3d.f
diff --git a/dependencies/sibyll/sibyll2.3d.hpp b/modules/sibyll/sibyll2.3d.hpp
similarity index 92%
rename from dependencies/sibyll/sibyll2.3d.hpp
rename to modules/sibyll/sibyll2.3d.hpp
index 3df0f7115d313cfaee9f8ef0aad91f88c5453536..09c7a4cc893864cfd6a8a1075bdb3746224b7053 100644
--- a/dependencies/sibyll/sibyll2.3d.hpp
+++ b/modules/sibyll/sibyll2.3d.hpp
@@ -8,16 +8,18 @@
 
 #pragma once
 
-/**
- * \function sibyll::rndm_interface
- *
- * this is the random number hook to external packages.
- *
- * CORSIKA8, for example, has to provide an implementation of this.
- **/
 namespace sibyll {
+
+  /**
+   * \function sibyll::rndm_interface
+   *
+   * this is the random number hook to external packages.
+   *
+   * CORSIKA8, for example, has to provide an implementation of this.
+   **/
   extern double rndm_interface();
-}
+
+} // namespace sibyll
 
 //----------------------------------------------
 //  C++ interface for the SIBYLL event generator
diff --git a/dependencies/sibyll/signuc.f b/modules/sibyll/signuc.f
similarity index 100%
rename from dependencies/sibyll/signuc.f
rename to modules/sibyll/signuc.f
diff --git a/dependencies/urqmd/CMakeLists.txt b/modules/urqmd/CMakeLists.txt
similarity index 61%
rename from dependencies/urqmd/CMakeLists.txt
rename to modules/urqmd/CMakeLists.txt
index 45b7c244a4ede4722c9a1df0dc9feac755eec9bf..4c37ed1e0cd735cc3dca3364570e84dee550b5c0 100644
--- a/dependencies/urqmd/CMakeLists.txt
+++ b/modules/urqmd/CMakeLists.txt
@@ -1,8 +1,9 @@
-#cmake_minimum_required(VERSION 3.1)
-#project(libUrQMD)
+cmake_minimum_required (VERSION 3.1)
+project (libUrQMD)
 
 set (
   MODEL_SOURCES
+  urqmd.cpp
   urqmdInterface.F
   addpart.f
   angdis.f
@@ -38,14 +39,17 @@ set (
 
 set (
   MODEL_HEADERS
+  urqmd.hpp
   )
 
-enable_language(Fortran)
+enable_language (Fortran)
 add_library (UrQMD SHARED ${MODEL_SOURCES})
-set_property(TARGET UrQMD PROPERTY POSITION_INDEPENDENT_CODE 1)
+target_include_directories (UrQMD PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+set_target_properties (UrQMD PROPERTIES POSITION_INDEPENDENT_CODE 1)
 
 add_library (UrQMD_static STATIC ${MODEL_SOURCES})
-set_property(TARGET UrQMD_static PROPERTY POSITION_INDEPENDENT_CODE 1)
+target_include_directories (UrQMD_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+set_target_properties (UrQMD_static PROPERTIES POSITION_INDEPENDENT_CODE 1)
 
 
 # add UrQMD to CORSIKA8 build
diff --git a/dependencies/urqmd/Copyright b/modules/urqmd/Copyright
similarity index 100%
rename from dependencies/urqmd/Copyright
rename to modules/urqmd/Copyright
diff --git a/dependencies/urqmd/README b/modules/urqmd/README
similarity index 100%
rename from dependencies/urqmd/README
rename to modules/urqmd/README
diff --git a/dependencies/urqmd/addpart.f b/modules/urqmd/addpart.f
similarity index 100%
rename from dependencies/urqmd/addpart.f
rename to modules/urqmd/addpart.f
diff --git a/dependencies/urqmd/angdis.f b/modules/urqmd/angdis.f
similarity index 100%
rename from dependencies/urqmd/angdis.f
rename to modules/urqmd/angdis.f
diff --git a/dependencies/urqmd/anndec.f b/modules/urqmd/anndec.f
similarity index 100%
rename from dependencies/urqmd/anndec.f
rename to modules/urqmd/anndec.f
diff --git a/dependencies/urqmd/blockres.f b/modules/urqmd/blockres.f
similarity index 100%
rename from dependencies/urqmd/blockres.f
rename to modules/urqmd/blockres.f
diff --git a/dependencies/urqmd/boxinc.f b/modules/urqmd/boxinc.f
similarity index 100%
rename from dependencies/urqmd/boxinc.f
rename to modules/urqmd/boxinc.f
diff --git a/dependencies/urqmd/boxprg.f b/modules/urqmd/boxprg.f
similarity index 100%
rename from dependencies/urqmd/boxprg.f
rename to modules/urqmd/boxprg.f
diff --git a/dependencies/urqmd/cascinit.f b/modules/urqmd/cascinit.f
similarity index 100%
rename from dependencies/urqmd/cascinit.f
rename to modules/urqmd/cascinit.f
diff --git a/dependencies/urqmd/colltab.f b/modules/urqmd/colltab.f
similarity index 100%
rename from dependencies/urqmd/colltab.f
rename to modules/urqmd/colltab.f
diff --git a/dependencies/urqmd/coload.f b/modules/urqmd/coload.f
similarity index 100%
rename from dependencies/urqmd/coload.f
rename to modules/urqmd/coload.f
diff --git a/dependencies/urqmd/comnorm.f b/modules/urqmd/comnorm.f
similarity index 100%
rename from dependencies/urqmd/comnorm.f
rename to modules/urqmd/comnorm.f
diff --git a/dependencies/urqmd/comres.f b/modules/urqmd/comres.f
similarity index 100%
rename from dependencies/urqmd/comres.f
rename to modules/urqmd/comres.f
diff --git a/dependencies/urqmd/coms.f b/modules/urqmd/coms.f
similarity index 100%
rename from dependencies/urqmd/coms.f
rename to modules/urqmd/coms.f
diff --git a/dependencies/urqmd/comstr.f b/modules/urqmd/comstr.f
similarity index 100%
rename from dependencies/urqmd/comstr.f
rename to modules/urqmd/comstr.f
diff --git a/dependencies/urqmd/comwid.f b/modules/urqmd/comwid.f
similarity index 100%
rename from dependencies/urqmd/comwid.f
rename to modules/urqmd/comwid.f
diff --git a/dependencies/urqmd/dectim.f b/modules/urqmd/dectim.f
similarity index 100%
rename from dependencies/urqmd/dectim.f
rename to modules/urqmd/dectim.f
diff --git a/dependencies/urqmd/delpart.f b/modules/urqmd/delpart.f
similarity index 100%
rename from dependencies/urqmd/delpart.f
rename to modules/urqmd/delpart.f
diff --git a/dependencies/urqmd/detbal.f b/modules/urqmd/detbal.f
similarity index 100%
rename from dependencies/urqmd/detbal.f
rename to modules/urqmd/detbal.f
diff --git a/dependencies/urqmd/dwidth.f b/modules/urqmd/dwidth.f
similarity index 100%
rename from dependencies/urqmd/dwidth.f
rename to modules/urqmd/dwidth.f
diff --git a/dependencies/urqmd/error.f b/modules/urqmd/error.f
similarity index 100%
rename from dependencies/urqmd/error.f
rename to modules/urqmd/error.f
diff --git a/dependencies/urqmd/freezeout.f b/modules/urqmd/freezeout.f
similarity index 100%
rename from dependencies/urqmd/freezeout.f
rename to modules/urqmd/freezeout.f
diff --git a/dependencies/urqmd/getmass.f b/modules/urqmd/getmass.f
similarity index 100%
rename from dependencies/urqmd/getmass.f
rename to modules/urqmd/getmass.f
diff --git a/dependencies/urqmd/getspin.f b/modules/urqmd/getspin.f
similarity index 100%
rename from dependencies/urqmd/getspin.f
rename to modules/urqmd/getspin.f
diff --git a/dependencies/urqmd/init.f b/modules/urqmd/init.f
similarity index 100%
rename from dependencies/urqmd/init.f
rename to modules/urqmd/init.f
diff --git a/dependencies/urqmd/inputs.f b/modules/urqmd/inputs.f
similarity index 100%
rename from dependencies/urqmd/inputs.f
rename to modules/urqmd/inputs.f
diff --git a/dependencies/urqmd/iso.f b/modules/urqmd/iso.f
similarity index 100%
rename from dependencies/urqmd/iso.f
rename to modules/urqmd/iso.f
diff --git a/dependencies/urqmd/ityp2pdg.f b/modules/urqmd/ityp2pdg.f
similarity index 100%
rename from dependencies/urqmd/ityp2pdg.f
rename to modules/urqmd/ityp2pdg.f
diff --git a/dependencies/urqmd/jdecay2.f b/modules/urqmd/jdecay2.f
similarity index 100%
rename from dependencies/urqmd/jdecay2.f
rename to modules/urqmd/jdecay2.f
diff --git a/dependencies/urqmd/make22.f b/modules/urqmd/make22.f
similarity index 100%
rename from dependencies/urqmd/make22.f
rename to modules/urqmd/make22.f
diff --git a/dependencies/urqmd/newpart.f b/modules/urqmd/newpart.f
similarity index 100%
rename from dependencies/urqmd/newpart.f
rename to modules/urqmd/newpart.f
diff --git a/dependencies/urqmd/numrec.f b/modules/urqmd/numrec.f
similarity index 100%
rename from dependencies/urqmd/numrec.f
rename to modules/urqmd/numrec.f
diff --git a/dependencies/urqmd/options.f b/modules/urqmd/options.f
similarity index 100%
rename from dependencies/urqmd/options.f
rename to modules/urqmd/options.f
diff --git a/dependencies/urqmd/outcom.f b/modules/urqmd/outcom.f
similarity index 100%
rename from dependencies/urqmd/outcom.f
rename to modules/urqmd/outcom.f
diff --git a/dependencies/urqmd/output.f b/modules/urqmd/output.f
similarity index 100%
rename from dependencies/urqmd/output.f
rename to modules/urqmd/output.f
diff --git a/dependencies/urqmd/paulibl.f b/modules/urqmd/paulibl.f
similarity index 100%
rename from dependencies/urqmd/paulibl.f
rename to modules/urqmd/paulibl.f
diff --git a/dependencies/urqmd/proppot.f b/modules/urqmd/proppot.f
similarity index 100%
rename from dependencies/urqmd/proppot.f
rename to modules/urqmd/proppot.f
diff --git a/dependencies/urqmd/saveinfo.f b/modules/urqmd/saveinfo.f
similarity index 100%
rename from dependencies/urqmd/saveinfo.f
rename to modules/urqmd/saveinfo.f
diff --git a/dependencies/urqmd/scatter.f b/modules/urqmd/scatter.f
similarity index 100%
rename from dependencies/urqmd/scatter.f
rename to modules/urqmd/scatter.f
diff --git a/dependencies/urqmd/siglookup.f b/modules/urqmd/siglookup.f
similarity index 100%
rename from dependencies/urqmd/siglookup.f
rename to modules/urqmd/siglookup.f
diff --git a/dependencies/urqmd/string.f b/modules/urqmd/string.f
similarity index 100%
rename from dependencies/urqmd/string.f
rename to modules/urqmd/string.f
diff --git a/dependencies/urqmd/tabinit.f b/modules/urqmd/tabinit.f
similarity index 100%
rename from dependencies/urqmd/tabinit.f
rename to modules/urqmd/tabinit.f
diff --git a/modules/urqmd/urqmd.cpp b/modules/urqmd/urqmd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..40a4b316561b506b9875bafc4701efead5eb53e1
--- /dev/null
+++ b/modules/urqmd/urqmd.cpp
@@ -0,0 +1,14 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <urqmd.hpp>
+
+namespace urqmd {
+  double ranf_(int&) { return urqmd::rndm_interface(); }
+}
+
diff --git a/dependencies/urqmd/urqmd.f b/modules/urqmd/urqmd.f
similarity index 100%
rename from dependencies/urqmd/urqmd.f
rename to modules/urqmd/urqmd.f
diff --git a/modules/urqmd/urqmd.hpp b/modules/urqmd/urqmd.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6da3d178b0bf402d9be09dcf4e8b363ac0976ba
--- /dev/null
+++ b/modules/urqmd/urqmd.hpp
@@ -0,0 +1,106 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <array>
+
+/**
+ * \function urqmd::rndm_interface
+ *
+ * this is the random number hook to external packages.
+ *
+ * CORSIKA8, for example, has to provide an implementation of this.
+ **/
+namespace urqmd {
+  extern double rndm_interface();
+
+  namespace constants {
+    // from coms.f
+    int constexpr nmax = 500;
+
+    // from options.f
+    int constexpr numcto = 400;
+    int constexpr numctp = 400;
+
+    // from inputs.f
+    int constexpr aamax = 300;
+
+  } // namespace constants
+
+  template <typename T>
+  using nmaxArray = std::array<T, constants::nmax>;
+  using nmaxIntArray = nmaxArray<int>;
+  using nmaxDoubleArray = nmaxArray<double>;
+
+  extern "C" {
+
+  void urqmd_(int&);
+  void iniurqmdc8_();
+  double ranf_(int&);
+  void cascinit_(int const&, int const&, int const&);
+  double nucrad_(int const&);
+  int pdgid_(int&, int&);
+  double sigtot_(int&, int&, double&);
+
+  // defined in coms.f
+  extern struct {
+    int npart, nbar, nmes, ctag, nsteps, uid_cnt, ranseed, event;
+    int Ap; // projectile mass number (in case of nucleus)
+    int At; // target mass number (in case of nucleus)
+    int Zp; // projectile charge number (in case of nucleus)
+    int Zt; // target charge number (in case of nucleus)
+    int eos, dectag, NHardRes, NSoftRes, NDecRes, NElColl, NBlColl;
+  } sys_;
+
+  extern struct {
+    double time, acttime, bdist, bimp, bmin;
+    double ebeam; // lab-frame energy of projectile
+    double ecm;
+  } rsys_;
+
+  // defined in coms.f
+  extern struct {
+    nmaxIntArray spin, ncoll, charge, ityp, lstcoll, iso3, origin, strid, uid;
+  } isys_;
+
+  // defined in coor.f
+  extern struct {
+    nmaxDoubleArray r0, rx, ry, rz, p0, px, py, pz, fmass, rww, dectime;
+  } coor_;
+
+  // defined in inputs.f
+  extern struct {
+    int nevents;
+    std::array<int, 2> spityp; // particle codes of: [0]: projectile, [1]: target
+    int prspflg;               // projectile special flag
+    int trspflg; // target special flag, set to 1 unless target is nucleus > H
+    std::array<int, 2> spiso3; // particle codes of: [0]: projectile, [1]: target
+    int outsteps, bflag, srtflag, efuncflag, nsrt, npb, firstev;
+  } inputs_;
+
+  // defined in inputs.f
+  extern struct {
+    double srtmin, srtmax, pbeam, betann, betatar, betapro, pbmin, pbmax;
+  } input2_;
+
+  // defined in options.f
+  extern struct {
+    std::array<double, constants::numcto> CTOption;
+    std::array<double, constants::numctp> CTParam;
+  } options_;
+
+  extern struct {
+    int fixedseed, bf13, bf14, bf15, bf16, bf17, bf18, bf19, bf20;
+  } loptions_;
+
+  // defined in urqmdInterface.F
+  extern struct { std::array<double, 3> xs, bim; } cxs_u2_;
+  }
+
+} // namespace urqmd
diff --git a/dependencies/urqmd/urqmdInterface.F b/modules/urqmd/urqmdInterface.F
similarity index 100%
rename from dependencies/urqmd/urqmdInterface.F
rename to modules/urqmd/urqmdInterface.F
diff --git a/dependencies/urqmd/urqmd_xs.cc b/modules/urqmd/urqmd_xs.cc
similarity index 100%
rename from dependencies/urqmd/urqmd_xs.cc
rename to modules/urqmd/urqmd_xs.cc
diff --git a/dependencies/urqmd/whichres.f b/modules/urqmd/whichres.f
similarity index 100%
rename from dependencies/urqmd/whichres.f
rename to modules/urqmd/whichres.f
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9adc82d8c191680b943437da972f5bc6b3814851
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory (framework/core) 
+add_subdirectory (modules/sibyll) 
+add_subdirectory (modules/qgsjetII) 
diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt
deleted file mode 100644
index 8b137891791fe96927ad78e64b0aad7bded08bdc..0000000000000000000000000000000000000000
--- a/src/Main/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/corsika/framework/CMakeLists.txt b/src/framework/core/CMakeLists.txt
similarity index 78%
rename from corsika/framework/CMakeLists.txt
rename to src/framework/core/CMakeLists.txt
index 8fabe1c93e381b10c7f82daa2788b5ed0f2e0a4a..3cbc13ae968c1975084ae1d44692325fd20eba9b 100644
--- a/corsika/framework/CMakeLists.txt
+++ b/src/framework/core/CMakeLists.txt
@@ -1,4 +1,4 @@
-set (input_dir ${PROJECT_SOURCE_DIR}/corsika/framework/core)
+set (input_dir ${PROJECT_SOURCE_DIR}/src/framework/core)
 set (output_dir ${PROJECT_BINARY_DIR}/corsika/framework/core)
 
 file (MAKE_DIRECTORY ${output_dir})
@@ -6,7 +6,9 @@ file (MAKE_DIRECTORY ${output_dir})
 add_custom_command (
   OUTPUT  ${output_dir}/GeneratedParticleProperties.inc
           ${output_dir}/particle_db.pkl
-  COMMAND ${input_dir}/pdxml_reader.py ${input_dir}/ParticleData.xml ${input_dir}/NuclearData.xml  ${input_dir}/ParticleClassNames.xml
+  COMMAND ${input_dir}/pdxml_reader.py ${input_dir}/ParticleData.xml
+                                       ${input_dir}/NuclearData.xml
+                                       ${input_dir}/ParticleClassNames.xml
   DEPENDS ${input_dir}/pdxml_reader.py
           ${input_dir}/ParticleData.xml
           ${input_dir}/NuclearData.xml
diff --git a/corsika/framework/core/NuclearData.xml b/src/framework/core/NuclearData.xml
similarity index 100%
rename from corsika/framework/core/NuclearData.xml
rename to src/framework/core/NuclearData.xml
diff --git a/corsika/framework/core/ParticleClassNames.xml b/src/framework/core/ParticleClassNames.xml
similarity index 100%
rename from corsika/framework/core/ParticleClassNames.xml
rename to src/framework/core/ParticleClassNames.xml
diff --git a/corsika/framework/core/ParticleData.xml b/src/framework/core/ParticleData.xml
similarity index 100%
rename from corsika/framework/core/ParticleData.xml
rename to src/framework/core/ParticleData.xml
diff --git a/corsika/framework/core/pdxml_reader.py b/src/framework/core/pdxml_reader.py
similarity index 100%
rename from corsika/framework/core/pdxml_reader.py
rename to src/framework/core/pdxml_reader.py
diff --git a/src/Main/shower.cpp b/src/main/shower.cc
similarity index 100%
rename from src/Main/shower.cpp
rename to src/main/shower.cc
diff --git a/corsika/modules/qgsjetII/CMakeLists.txt b/src/modules/qgsjetII/CMakeLists.txt
similarity index 71%
rename from corsika/modules/qgsjetII/CMakeLists.txt
rename to src/modules/qgsjetII/CMakeLists.txt
index f9b083cd192ef729d9542883ddb2bf16f68e4138..297e2690ddf4119494eb2736aa68293109699c69 100644
--- a/corsika/modules/qgsjetII/CMakeLists.txt
+++ b/src/modules/qgsjetII/CMakeLists.txt
@@ -1,4 +1,4 @@
-set (input_dir ${PROJECT_SOURCE_DIR}/corsika/modules/qgsjetII)
+set (input_dir ${PROJECT_SOURCE_DIR}/src/modules/qgsjetII)
 set (output_dir ${PROJECT_BINARY_DIR}/corsika/modules/qgsjetII)
 
 file (MAKE_DIRECTORY ${output_dir})
@@ -8,11 +8,11 @@ add_custom_command (
   COMMAND ${input_dir}/code_generator.py 
           ${PROJECT_BINARY_DIR}/corsika/framework/core/particle_db.pkl
           ${input_dir}/qgsjet-II-04-codes.dat
-  DEPENDS code_generator.py
-          ${PROJECT_BINARY_DIR}/corsika/framework/core/particle_db.pkl
-          qgsjet-II-04-codes.dat
+  DEPENDS ${input_dir}/code_generator.py
+          ${input_dir}/qgsjet-II-04-codes.dat
+          GenParticlesHeaders # for particle_db.pkl
   WORKING_DIRECTORY
-          ${output_dir}/
+          ${output_dir}
   COMMENT "Generate conversion tables for particle codes QGSJetII <-> CORSIKA"
   VERBATIM
   )
diff --git a/corsika/modules/qgsjetII/code_generator.py b/src/modules/qgsjetII/code_generator.py
similarity index 100%
rename from corsika/modules/qgsjetII/code_generator.py
rename to src/modules/qgsjetII/code_generator.py
diff --git a/corsika/modules/qgsjetII/qgsjet-II-04-codes.dat b/src/modules/qgsjetII/qgsjet-II-04-codes.dat
similarity index 100%
rename from corsika/modules/qgsjetII/qgsjet-II-04-codes.dat
rename to src/modules/qgsjetII/qgsjet-II-04-codes.dat
diff --git a/corsika/modules/sibyll/CMakeLists.txt b/src/modules/sibyll/CMakeLists.txt
similarity index 74%
rename from corsika/modules/sibyll/CMakeLists.txt
rename to src/modules/sibyll/CMakeLists.txt
index 7982d74c39f0dfe08017515fbcdeeffd6990473a..c2e6dd0bfc4840f59f4ce33a981186bdcff3b248 100644
--- a/corsika/modules/sibyll/CMakeLists.txt
+++ b/src/modules/sibyll/CMakeLists.txt
@@ -1,4 +1,4 @@
-set (input_dir ${PROJECT_SOURCE_DIR}/corsika/modules/sibyll)
+set (input_dir ${PROJECT_SOURCE_DIR}/src/modules/sibyll)
 set (output_dir ${PROJECT_BINARY_DIR}/corsika/modules/sibyll)
 
 file (MAKE_DIRECTORY ${output_dir})
@@ -8,9 +8,9 @@ add_custom_command (
   COMMAND ${input_dir}/code_generator.py 
           ${PROJECT_BINARY_DIR}/corsika/framework/core/particle_db.pkl
           ${input_dir}/sibyll_codes.dat
-  DEPENDS code_generator.py
-          ${PROJECT_BINARY_DIR}/corsika/framework/core/particle_db.pkl
-          sibyll_codes.dat
+  DEPENDS ${input_dir}/code_generator.py
+          ${input_dir}/sibyll_codes.dat
+          GenParticlesHeaders # for particle_db.pkl
   WORKING_DIRECTORY
           ${output_dir}/
   COMMENT "Generate conversion tables for particle codes SIBYLL <-> CORSIKA"
diff --git a/corsika/modules/sibyll/code_generator.py b/src/modules/sibyll/code_generator.py
similarity index 100%
rename from corsika/modules/sibyll/code_generator.py
rename to src/modules/sibyll/code_generator.py
diff --git a/corsika/modules/sibyll/sibyll_codes.dat b/src/modules/sibyll/sibyll_codes.dat
similarity index 100%
rename from corsika/modules/sibyll/sibyll_codes.dat
rename to src/modules/sibyll/sibyll_codes.dat
diff --git a/tests/framework/CMakeLists.txt b/tests/framework/CMakeLists.txt
index d62ee295f8c4c55e2846f55cac86c65c602a5814..55458f17694702f7034f92ea1c96abed6fdc92f1 100644
--- a/tests/framework/CMakeLists.txt
+++ b/tests/framework/CMakeLists.txt
@@ -1,5 +1,5 @@
 
-set (sources
+set (test_framework_sources
   # testCascade.cpp this is most important, but whole content of former Processes folder missing yet
   testCombinedStack.cpp
   testCOMBoost.cpp
@@ -16,23 +16,4 @@ set (sources
   testUnits.cpp
   )
 
-
-add_executable (testFramework ${sources})
-
-target_link_libraries (testFramework CORSIKA8 Catch2)
-
-target_compile_options (testFramework PRIVATE -g) # do not skip asserts
-
-target_include_directories (testFramework PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-
-file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/test_outputs/)
-
-if (CORSIKA_SANITIZERS_ENABLED)
-  # -O1 is suggested in clang docs to get reasonable performance
-  target_compile_options (${name} PRIVATE -O1 -fno-omit-frame-pointer -fsanitize=${sanitize} -fno-sanitize-recover=all)
-  set_target_properties (${name} PROPERTIES LINK_FLAGS "-fsanitize=${sanitize}")
-endif ()
-
-add_test (
-  NAME testFramework
-  COMMAND testFramework -o ${PROJECT_BINARY_DIR}/test_outputs/junit-${name}.xml -s -r junit)
+CORSIKA_ADD_TEST (testFramework SOURCES ${test_framework_sources})
diff --git a/tests/framework/TestMain.cpp b/tests/framework/TestMain.cpp
index fa52fa804f307c546f628b7ccd5d14401b6f0adb..51532584b8e03b35d79301543ac8f80b598ba544 100644
--- a/tests/framework/TestMain.cpp
+++ b/tests/framework/TestMain.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/framework/testCOMBoost.cpp b/tests/framework/testCOMBoost.cpp
index 58beafd5255babfe8cca016566ed1128779e5c4e..52f666d0924eeffad2e7c5d7853f36069005f958 100644
--- a/tests/framework/testCOMBoost.cpp
+++ b/tests/framework/testCOMBoost.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -17,10 +17,6 @@
 #include <iostream>
 
 using namespace corsika;
-using namespace corsika;
-using namespace corsika::units::si;
-using corsika::units::constants::c;
-using corsika::units::constants::cSquared;
 
 double constexpr absMargin = 1e-6;
 
diff --git a/tests/framework/testCascade.cpp b/tests/framework/testCascade.cpp
index 3caaf74842d763673030be9be93c8e5221bca5c9..03e360ea1e41e27c94e33b7a4db2a8711c55b325 100644
--- a/tests/framework/testCascade.cpp
+++ b/tests/framework/testCascade.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/framework/testCascade.hpp b/tests/framework/testCascade.hpp
index e44298adf37c9aaa416864f29fc6b73f5670ea1e..85863e03c4f83ac247167dac1e0664d677fbdceb 100644
--- a/tests/framework/testCascade.hpp
+++ b/tests/framework/testCascade.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/framework/testCombinedStack.cpp b/tests/framework/testCombinedStack.cpp
index 43da9a9e78831249ca597c1ae1012c967b211016..a50be568b7f3998cbf1ed07528aafba730826ced 100644
--- a/tests/framework/testCombinedStack.cpp
+++ b/tests/framework/testCombinedStack.cpp
@@ -6,22 +6,20 @@
  * the license.
  */
 
+#define protected public // to also test the internal state of objects
+
 #include <corsika/framework/stack/CombinedStack.hpp>
 #include <corsika/framework/stack/SecondaryView.hpp>
 #include <corsika/framework/stack/Stack.hpp>
 
-#include <boost/type_index.hpp>
-#include <type_traits>
-
-#include <tests/framework/testTestStack.h> // for testing: simple stack. This is a
-using boost::typeindex::type_id_with_cvr;
+#include <testTestStack.h> // for testing: simple stack. This is a
+// test-build, and inluce file is obtained from CMAKE_CURRENT_SOURCE_DIR
 
 #include <iomanip>
 #include <vector>
 
 #include <catch2/catch.hpp>
 
-using namespace corsika;
 using namespace corsika;
 using namespace std;
 
@@ -82,8 +80,8 @@ public:
 // combined stack: StackTest = (TestStackData + TestStackData2)
 template <typename StackIter>
 using CombinedTestInterfaceType =
-    corsika::CombinedParticleInterface<TestParticleInterface, TestParticleInterface2,
-                                       StackIter>;
+    corsika::CombinedParticleInterface<TestParticleInterface,
+                                              TestParticleInterface2, StackIter>;
 
 using StackTest = CombinedStack<TestStackData, TestStackData2, CombinedTestInterfaceType>;
 
@@ -277,8 +275,8 @@ public:
 // combined stack
 template <typename StackIter>
 using CombinedTestInterfaceType2 =
-    corsika::CombinedParticleInterface<StackTest::PIType, TestParticleInterface3,
-                                       StackIter>;
+    corsika::CombinedParticleInterface<StackTest::MPIType, TestParticleInterface3,
+                                              StackIter>;
 
 using StackTest2 = CombinedStack<typename StackTest::StackImpl, TestStackData3,
                                  CombinedTestInterfaceType2>;
@@ -363,8 +361,8 @@ TEST_CASE("Combined Stack - multi", "[stack]") {
  */
 template <typename StackIter>
 using CombinedTestInterfaceType2 =
-    corsika::CombinedParticleInterface<StackTest::PIType, TestParticleInterface3,
-                                       StackIter>;
+    corsika::CombinedParticleInterface<StackTest::MPIType, TestParticleInterface3,
+                                              StackIter>;
 
 using StackTest2 = CombinedStack<typename StackTest::StackImpl, TestStackData3,
                                  CombinedTestInterfaceType2>;
diff --git a/tests/framework/testCorsikaFenv.cpp b/tests/framework/testCorsikaFenv.cpp
index 323c0fa18c02cff33f7fdfdc9aedfbf67c5345e1..e4ec2eff44264cb30a33780bd1e7c387f6cac60f 100644
--- a/tests/framework/testCorsikaFenv.cpp
+++ b/tests/framework/testCorsikaFenv.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/framework/testFourVector.cpp b/tests/framework/testFourVector.cpp
index 6623eb7ca72434d7f32407231fb954dfb0b39036..c17fb3695b2937ebde2301b76c13f8301b39033a 100644
--- a/tests/framework/testFourVector.cpp
+++ b/tests/framework/testFourVector.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -75,7 +75,7 @@ TEST_CASE("four vectors") {
    */
   SECTION("Energy momentum in SI-units") {
 
-    auto E1 = 100_GeV / corsika::units::constants::c;
+    auto E1 = 100_GeV / constants::c;
     Vector<hepmomentum_d> P1(rootCS, {10_GeV, 5_GeV, 15_GeV});
 
     FourVector p1(E1, P1);
@@ -92,7 +92,7 @@ TEST_CASE("four vectors") {
    */
   SECTION("Spacetime in SI-units") {
 
-    TimeType T2 = 10_m / corsika::units::constants::c;
+    TimeType T2 = 10_m / constants::c;
     Vector<length_d> P2(rootCS, {10_m, 5_m, 5_m});
 
     const double check = 10 * 10 - 10 * 10 - 5 * 5 - 5 * 5; // for dummies...
@@ -160,10 +160,10 @@ TEST_CASE("four vectors") {
 
   SECTION("Use as wrapper") {
 
-    TimeType T = 10_m / corsika::units::constants::c;
+    TimeType T = 10_m / constants::c;
     Vector<length_d> P(rootCS, {10_m, 5_m, 5_m});
 
-    const TimeType T_c = 10_m / corsika::units::constants::c;
+    const TimeType T_c = 10_m / constants::c;
     const Vector<length_d> P_c(rootCS, {10_m, 5_m, 5_m});
 
     // FourVector<TimeType&, Vector<length_d>&> p0(T_c, P_c); // this does not compile,
diff --git a/tests/framework/testGeometry.cpp b/tests/framework/testGeometry.cpp
index c6b0b68e3d8ab268cf32792f76d1a1cf236cf7b8..d7d27539a7a9e649abb76064be846afd86cc6111 100644
--- a/tests/framework/testGeometry.cpp
+++ b/tests/framework/testGeometry.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/framework/testParticles.cpp b/tests/framework/testParticles.cpp
index 9d13c2cac3bf0c130f94ef8ff7f70beef868d2ee..f593750d8bc4884e560e00f64bcc991141fadcf4 100644
--- a/tests/framework/testParticles.cpp
+++ b/tests/framework/testParticles.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -30,9 +30,8 @@ TEST_CASE("ParticleProperties", "[Particles]") {
     CHECK(Electron::GetMass() / (511_keV) == Approx(1));
     CHECK(Electron::GetMass() / GetMass(Code::Electron) == Approx(1));
 
-    CHECK((Proton::GetMass() + Neutron::GetMass()) /
-              corsika::units::constants::nucleonMass ==
-          Approx(2));
+    REQUIRE((Proton::GetMass() + Neutron::GetMass()) / constants::nucleonMass ==
+            Approx(2));
   }
 
   SECTION("Charges") {
@@ -69,15 +68,15 @@ TEST_CASE("ParticleProperties", "[Particles]") {
   }
 
   SECTION("Lifetimes") {
-    CHECK(GetLifetime(Code::Electron) ==
-          std::numeric_limits<double>::infinity() * corsika::units::si::second);
-    CHECK(GetLifetime(Code::DPlus) < GetLifetime(Code::Gamma));
-    CHECK(GetLifetime(Code::RhoPlus) / corsika::units::si::second ==
-          (Approx(4.414566727909413e-24).epsilon(1e-3)));
-    CHECK(GetLifetime(Code::SigmaMinusBar) / corsika::units::si::second ==
-          (Approx(8.018880848563575e-11).epsilon(1e-5)));
-    CHECK(GetLifetime(Code::MuPlus) / corsika::units::si::second ==
-          (Approx(2.1970332555864364e-06).epsilon(1e-5)));
+    REQUIRE(GetLifetime(Code::Electron) ==
+            std::numeric_limits<double>::infinity() * si::second);
+    REQUIRE(GetLifetime(Code::DPlus) < GetLifetime(Code::Gamma));
+    REQUIRE(GetLifetime(Code::RhoPlus) / si::second ==
+            (Approx(4.414566727909413e-24).epsilon(1e-3)));
+    REQUIRE(GetLifetime(Code::SigmaMinusBar) / si::second ==
+            (Approx(8.018880848563575e-11).epsilon(1e-5)));
+    REQUIRE(GetLifetime(Code::MuPlus) / si::second ==
+            (Approx(2.1970332555864364e-06).epsilon(1e-5)));
   }
 
   SECTION("Particle groups: electromagnetic") {
diff --git a/tests/framework/testProcessSequence.cpp b/tests/framework/testProcessSequence.cpp
index f506d57014130a1ac37e99ec3cc99faeb1004923..e63b69ea97fd0f6a8e17d6fdf5ffd173746babfc 100644
--- a/tests/framework/testProcessSequence.cpp
+++ b/tests/framework/testProcessSequence.cpp
@@ -1,11 +1,13 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
+#include <corsika/framework/process/ProcessSequence.hpp>
+
 #include <catch2/catch.hpp>
 
 #include <array>
@@ -13,9 +15,6 @@
 #include <iostream>
 #include <typeinfo>
 
-#include <corsika/framework/sequence/ProcessSequence.hpp>
-//#include <corsika/process/SwitchProcess.hpp>
-
 using namespace corsika;
 using namespace corsika::units::si;
 using namespace corsika;
diff --git a/tests/framework/testRandom.cpp b/tests/framework/testRandom.cpp
index 5a8bcb0f52b678c23974c919a671a6cdf594849a..7a894c9e0c3b0b4c7679fd007bbe76e32effefb4 100644
--- a/tests/framework/testRandom.cpp
+++ b/tests/framework/testRandom.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/framework/testSecondaryView.cpp b/tests/framework/testSecondaryView.cpp
index ab8f1a85dc3c5dd62c4f6349668d3e247627d5df..7d881da4ea8dfe5c296e5ba8e6915db56aa5e23f 100644
--- a/tests/framework/testSecondaryView.cpp
+++ b/tests/framework/testSecondaryView.cpp
@@ -6,14 +6,13 @@
  * the license.
  */
 
+#define protected public // to also test the internal state of objects
+
 #include <corsika/framework/stack/SecondaryView.hpp>
 #include <corsika/framework/stack/Stack.hpp>
 
-#include <boost/type_index.hpp>
-#include <type_traits>
-
-#include <tests/framework/testTestStack.h> // for testing: simple stack. This is a
-using boost::typeindex::type_id_with_cvr;
+#include <testTestStack.h> // for testing: simple stack. This is a
+// test-build, and inluce file is obtained from CMAKE_CURRENT_SOURCE_DIR
 
 #include <iomanip>
 #include <vector>
@@ -21,7 +20,7 @@ using boost::typeindex::type_id_with_cvr;
 #include <catch2/catch.hpp>
 
 using namespace corsika;
-using namespace corsika;
+using namespace corsika::stack;
 using namespace std;
 
 typedef Stack<TestStackData, TestParticleInterface> StackTest;
diff --git a/tests/framework/testStackInterface.cpp b/tests/framework/testStackInterface.cpp
index 5e34a0560d813e8f35f7fa4dfa74e61e313f0f64..eab48ec9758cce112292183004c84cf6e5de4f1b 100644
--- a/tests/framework/testStackInterface.cpp
+++ b/tests/framework/testStackInterface.cpp
@@ -6,13 +6,13 @@
  * the license.
  */
 
-#include <corsika/framework/stack/Stack.hpp>
+#define protected public // to also test the internal state of objects
 
-#include <boost/type_index.hpp>
-#include <type_traits>
+#include <corsika/framework/stack/Stack.hpp>
 
-#include <tests/framework/testTestStack.h> // simple test-stack for testing. This is
-using boost::typeindex::type_id_with_cvr;
+#include <testTestStack.h> // simple test-stack for testing. This is
+                           // for testing only: include from
+                           // CMAKE_CURRENT_SOURCE_DIR
 
 #include <iomanip>
 #include <tuple>
@@ -20,7 +20,6 @@ using boost::typeindex::type_id_with_cvr;
 
 #include <catch2/catch.hpp>
 
-using namespace corsika;
 using namespace corsika;
 using namespace std;
 
diff --git a/tests/framework/testTestStack.h b/tests/framework/testTestStack.h
index 9aaa63320bace8b506969df71b90e3a41873b230..e9e3e96455718516fe6703cc8639741ecd131a55 100644
--- a/tests/framework/testTestStack.h
+++ b/tests/framework/testTestStack.h
@@ -59,11 +59,12 @@ private:
  *
  */
 template <typename StackIteratorInterface>
-class TestParticleInterface : public corsika::ParticleBase<StackIteratorInterface> {
+class TestParticleInterface
+    : public corsika::stack::ParticleBase<StackIteratorInterface> {
 
 public:
-  using corsika::ParticleBase<StackIteratorInterface>::GetStackData;
-  using corsika::ParticleBase<StackIteratorInterface>::GetIndex;
+  using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData;
+  using corsika::stack::ParticleBase<StackIteratorInterface>::GetIndex;
 
   /*
      The SetParticleData methods are called for creating new entries
diff --git a/tests/framework/testUnits.cpp b/tests/framework/testUnits.cpp
index 1bd307bde802beb52aa3f207f0975a12f2573b66..26f4f918ffe969aeced6af35b196e693bf1e72b9 100644
--- a/tests/framework/testUnits.cpp
+++ b/tests/framework/testUnits.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -130,17 +130,17 @@ TEST_CASE("PhysicalUnits", "[Units]") {
     REQUIRE((length / 1_fm) == Approx(1));
 
     TimeType const time = ConvertHEPToSI<TimeType::dimension_type>(invEnergy);
-    REQUIRE((time / (1_fm / corsika::units::constants::c)) == Approx(1));
+    REQUIRE((time / (1_fm / constants::c)) == Approx(1));
 
     auto const protonMass = 938.272'081'3_MeV; // convertible to mass or SI energy
     MassType protonMassSI = ConvertHEPToSI<MassType::dimension_type>(protonMass);
     REQUIRE((protonMassSI / 1.672'621'898e-27_kg) == Approx(1));
-    REQUIRE((protonMassSI / (1.007'276 * corsika::units::constants::u)) == Approx(1));
+    REQUIRE((protonMassSI / (1.007'276 * constants::u)) == Approx(1));
   }
 
   SECTION("SI/HEP conversion") {
-    REQUIRE(ConvertSIToHEP(units::constants::c) == Approx(1));
-    REQUIRE(ConvertSIToHEP(units::constants::hBar) == Approx(1));
+    REQUIRE(ConvertSIToHEP(constants::c) == Approx(1));
+    REQUIRE(ConvertSIToHEP(constants::hBar) == Approx(1));
 
     {
       auto const invLength = 1 / 197.326978_fm; // should be convertible to HEPEnergy
diff --git a/tests/media/CMakeLists.txt b/tests/media/CMakeLists.txt
index 25e0d35d356bdbd2dec49bcb273871cb9053d8a3..8870a7736772a2b18655938381457df686e2c1b7 100644
--- a/tests/media/CMakeLists.txt
+++ b/tests/media/CMakeLists.txt
@@ -1,26 +1,6 @@
-
-set (sources
+set (test_media_sources
   TestMain.cpp
   testEnvironment.cpp
   )
 
-
-add_executable (testEnvironment ${sources})
-
-target_link_libraries (testEnvironment CORSIKA8 Catch2)
-
-target_compile_options (testEnvironment PRIVATE -g) # do not skip asserts
-
-target_include_directories (testEnvironment PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-
-file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/test_outputs/)
-
-if (CORSIKA_SANITIZERS_ENABLED)
-  # -O1 is suggested in clang docs to get reasonable performance
-  target_compile_options (${name} PRIVATE -O1 -fno-omit-frame-pointer -fsanitize=${sanitize} -fno-sanitize-recover=all)
-  set_target_properties (${name} PROPERTIES LINK_FLAGS "-fsanitize=${sanitize}")
-endif ()
-
-add_test (
-  NAME testEnvironment
-  COMMAND testEnvironment -o ${PROJECT_BINARY_DIR}/test_outputs/junit-media.xml -s -r junit)
+CORSIKA_ADD_TEST (testMedia SOURCES ${test_media_sources})
diff --git a/tests/media/TestMain.cpp b/tests/media/TestMain.cpp
index da6f2c3f1a0f72b5af0d49771b908c57e6b51d3b..51532584b8e03b35d79301543ac8f80b598ba544 100644
--- a/tests/media/TestMain.cpp
+++ b/tests/media/TestMain.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/media/testEnvironment.cpp b/tests/media/testEnvironment.cpp
index bce84c8811aebe247bbaa90ce1abc5d8f86aa309..99f484d1087d1f21f135442b54c6d41bbcc012cd 100644
--- a/tests/media/testEnvironment.cpp
+++ b/tests/media/testEnvironment.cpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -46,7 +46,7 @@ TEST_CASE("FlatExponential") {
 
   Vector const axis(gCS, QuantityVector<dimensionless_d>(0, 0, 1));
   LengthType const lambda = 3_m;
-  auto const rho0 = 1_g / units::static_pow<3>(1_cm);
+  auto const rho0 = 1_g / static_pow<3>(1_cm);
   FlatExponential<IMediumModel> const medium(gOrigin, axis, rho0, lambda,
                                              protonComposition);
   auto const tEnd = 5_s;
@@ -100,7 +100,7 @@ TEST_CASE("SlidingPlanarExponential") {
                                              std::vector<float>{1.f});
 
   LengthType const lambda = 3_m;
-  auto const rho0 = 1_g / units::static_pow<3>(1_cm);
+  auto const rho0 = 1_g / static_pow<3>(1_cm);
   auto const tEnd = 5_s;
 
   SlidingPlanarExponential<IMediumModel> const medium(gOrigin, rho0, lambda,
@@ -139,7 +139,7 @@ struct Exponential {
 
   template <int N>
   auto Derivative(Point const& p, Vector<dimensionless_d> const& v) const {
-    return v.GetComponents()[0] * (*this)(p) / corsika::units::static_pow<N>(1_m);
+    return v.GetComponents()[0] * (*this)(p) / static_pow<N>(1_m);
   }
 
   auto FirstDerivative(Point const& p, Vector<dimensionless_d> const& v) const {
diff --git a/tests/modules/CMakeLists.txt b/tests/modules/CMakeLists.txt
index c042c5ed3901c030f37df77000156b60048c224e..15aa04f4bfb7db5e27a55c546ef434c312fa6f19 100644
--- a/tests/modules/CMakeLists.txt
+++ b/tests/modules/CMakeLists.txt
@@ -1,4 +1,3 @@
-
 set (test_modules_sources
   TestMain.cpp
   testSibyll.cpp
@@ -13,22 +12,5 @@ set (test_modules_sources
   testUrQMD.cpp
   )
 
-add_executable (testModules ${test_modules_sources})
-
-target_link_libraries (testModules CORSIKA8 Catch2)
-
-target_compile_options (testModules PRIVATE -g) # do not skip asserts
-
-target_include_directories (testModules PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-
-file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/test_outputs/)
-
-if (CORSIKA_SANITIZERS_ENABLED)
-  # -O1 is suggested in clang docs to get reasonable performance
-  target_compile_options (${name} PRIVATE -O1 -fno-omit-frame-pointer -fsanitize=${sanitize} -fno-sanitize-recover=all)
-  set_target_properties (${name} PROPERTIES LINK_FLAGS "-fsanitize=${sanitize}")
-endif ()
+CORSIKA_ADD_TEST (testModules SOURCES ${test_modules_sources})
 
-add_test (
-  NAME testModules
-  COMMAND testModules -o ${PROJECT_BINARY_DIR}/test_outputs/junit-modules.xml -s -r junit)
diff --git a/tests/modules/TestMain.cpp b/tests/modules/TestMain.cpp
index da6f2c3f1a0f72b5af0d49771b908c57e6b51d3b..51532584b8e03b35d79301543ac8f80b598ba544 100644
--- a/tests/modules/TestMain.cpp
+++ b/tests/modules/TestMain.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/modules/testNullModel.cpp b/tests/modules/testNullModel.cpp
index b59cd90048f4085e39ca2536f1a434935ae5681b..18b7ff6ba86c030d7243a890cc298e4f15e2ee41 100644
--- a/tests/modules/testNullModel.cpp
+++ b/tests/modules/testNullModel.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -10,7 +8,7 @@
 
 #include <catch2/catch.hpp>
 
-#include <corsika/modules/null_model/NullModel.hpp>
+#include <corsika/modules/NullModel.hpp>
 
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/RootCoordinateSystem.hpp>
diff --git a/tests/modules/testObservationPlane.cpp b/tests/modules/testObservationPlane.cpp
index f3f3d24b7337a5ce5f3591e6ef53116ffe4b0536..d757dabb6ddb3e7de6aa7583746523b3dbba1c3e 100644
--- a/tests/modules/testObservationPlane.cpp
+++ b/tests/modules/testObservationPlane.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -10,7 +8,7 @@
 
 #include <catch2/catch.hpp>
 
-#include <corsika/modules/observation_plane/ObservationPlane.hpp>
+#include <corsika/modules/ObservationPlane.hpp>
 
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/RootCoordinateSystem.hpp>
@@ -19,7 +17,6 @@
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
 
-using namespace corsika::units::si;
 using namespace corsika::observation_plane;
 using namespace corsika;
 
@@ -34,10 +31,10 @@ TEST_CASE("ContinuousProcess interface", "[proccesses][observation_plane]") {
    */
 
   Point const start(rootCS, {0_m, 1_m, 10_m});
-  Vector<units::si::SpeedType::dimension_type> vec(rootCS, 0_m / second, 0_m / second,
-                                                   -units::constants::c);
+  Vector<SpeedType::dimension_type> vec(rootCS, 0_m / second, 0_m / second,
+                                        -constants::c);
   Line line(start, vec);
-  Trajectory<Line> track(line, 12_m / units::constants::c);
+  Trajectory<Line> track(line, 12_m / constants::c);
 
   // setup particle stack, and add primary particle
   setup::Stack stack;
@@ -46,12 +43,12 @@ TEST_CASE("ContinuousProcess interface", "[proccesses][observation_plane]") {
     auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) {
       return sqrt((Elab - m) * (Elab + m));
     };
-    stack.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                                 Point, units::si::TimeType>{
-        Code::NuMu, 1_GeV,
-        corsika::MomentumVector(rootCS,
-                                {0_GeV, 0_GeV, -elab2plab(1_GeV, NuMu::GetMass())}),
-        Point(rootCS, {1_m, 1_m, 10_m}), 0_ns});
+    stack.AddParticle(
+        std::tuple<Code, HEPEnergyType, corsika::MomentumVector, Point, TimeType>{
+            Code::NuMu, 1_GeV,
+            corsika::MomentumVector(rootCS,
+                                    {0_GeV, 0_GeV, -elab2plab(1_GeV, NuMu::GetMass())}),
+            Point(rootCS, {1_m, 1_m, 10_m}), 0_ns});
   }
   auto particle = stack.GetNextParticle();
 
diff --git a/tests/modules/testParticleCut.cpp b/tests/modules/testParticleCut.cpp
index b9e2cda7c88c50148d1681eb76613c5423e8ffeb..ea00b5e5d45638c55e33a3c8cc73355bda9e6b1c 100644
--- a/tests/modules/testParticleCut.cpp
+++ b/tests/modules/testParticleCut.cpp
@@ -1,15 +1,12 @@
-
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
-#include <corsika/modules/particle_cut/ParticleCut.hpp>
+#include <corsika/modules/ParticleCut.hpp>
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Point.hpp>
diff --git a/tests/modules/testPythia8.cpp b/tests/modules/testPythia8.cpp
index 07cc2d930cb0378e81c352e8c1d22b5471f63ffd..1d6bb6d36585429f2367e618af38f60b514d71d3 100644
--- a/tests/modules/testPythia8.cpp
+++ b/tests/modules/testPythia8.cpp
@@ -1,22 +1,17 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
-#include <corsika/modules/pythia8/Decay.hpp>
-#include <corsika/modules/pythia8/Interaction.hpp>
-
-#include <corsika/framework/random/RNGManager.hpp>
+#include <corsika/modules/Pythia8.hpp>
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-
 #include <corsika/framework/geometry/Point.hpp>
+#include <corsika/framework/random/RNGManager.hpp>
 
 #include <catch2/catch.hpp>
 
diff --git a/tests/modules/testQGSJetII.cpp b/tests/modules/testQGSJetII.cpp
index 866dbfa8fc823d2b6c3c22efbefef748281bcb5c..be05439f29b64887d676004c095af66bbd434795 100644
--- a/tests/modules/testQGSJetII.cpp
+++ b/tests/modules/testQGSJetII.cpp
@@ -1,8 +1,6 @@
 /*
  * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
- * See file AUTHORS for a list of contributors.
- *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
@@ -68,8 +66,6 @@ TEST_CASE("QgsjetII", "[processes]") {
 #include <corsika/media/HomogeneousMedium.hpp>
 #include <corsika/media/NuclearComposition.hpp>
 
-using namespace corsika::units::si;
-
 TEST_CASE("QgsjetIIInterface", "[processes]") {
 
   // setup environment, geometry
@@ -103,11 +99,9 @@ TEST_CASE("QgsjetIIInterface", "[processes]") {
     auto plab = corsika::MomentumVector(cs, {0_GeV, 0_GeV, -P0});
     corsika::Point pos(cs, 0_m, 0_m, 0_m);
     auto particle = stack.AddParticle(
-        std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                   corsika::Point, units::si::TimeType, unsigned int, unsigned int>{
-            corsika::Code::Nucleus, E0, plab, pos, 0_ns, 16, 8});
-    // corsika::stack::MomentumVector, corsika::Point, units::si::TimeType>{
-    //	  corsika::Code::PiPlus, E0, plab, pos, 0_ns});
+        std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector, corsika::Point,
+                   TimeType, unsigned int, unsigned int>{corsika::Code::Nucleus, E0, plab,
+                                                         pos, 0_ns, 16, 8});
 
     particle.SetNode(nodePtr);
     corsika::SecondaryView view(particle);
diff --git a/tests/modules/testSibyll.cpp b/tests/modules/testSibyll.cpp
index 0fbb7dffd71518633810d47ba381dcc9bd1610ea..49be8dca49e4640ccd3e0c5cc21908c6622ffb43 100644
--- a/tests/modules/testSibyll.cpp
+++ b/tests/modules/testSibyll.cpp
@@ -6,18 +6,13 @@
  * the license.
  */
 
-#include <corsika/modules/sibyll/Decay.hpp>
-#include <corsika/modules/sibyll/Interaction.hpp>
-#include <corsika/modules/sibyll/NuclearInteraction.hpp>
+#include <corsika/modules/Sibyll.hpp>
 #include <corsika/modules/sibyll/ParticleConversion.hpp>
-#include <corsika/modules/sibyll/Random.hpp>
-
-#include <corsika/framework/random/RNGManager.hpp>
 
 #include <corsika/framework/core/ParticleProperties.hpp>
-
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Point.hpp>
+#include <corsika/framework/random/RNGManager.hpp>
 
 #include <catch2/catch.hpp>
 #include <tuple>
diff --git a/tests/modules/testStackInspector.cpp b/tests/modules/testStackInspector.cpp
index a2353092d9bc48b66839926b19dba5410964745e..77dde76059cd8f8e259ec106d46483e57d5d51f4 100644
--- a/tests/modules/testStackInspector.cpp
+++ b/tests/modules/testStackInspector.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -10,7 +8,7 @@
 
 #include <catch2/catch.hpp>
 
-#include <corsika/modules/stack_inspector/StackInspector.hpp>
+#include <corsika/modules/StackInspector.hpp>
 
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/RootCoordinateSystem.hpp>
diff --git a/tests/modules/testSwitchProcess.cpp b/tests/modules/testSwitchProcess.cpp
index 362abbc115199782ed1a8da6ef3e9a41e6c20a08..73bf7041dcd82217a1d610b94bc79920a75f1d20 100644
--- a/tests/modules/testSwitchProcess.cpp
+++ b/tests/modules/testSwitchProcess.cpp
@@ -1,17 +1,16 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
+#include <corsika/modules/SwitchProcess.hpp>
+
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/stack/SecondaryView.hpp>
 #include <corsika/framework/stack/Stack.hpp>
-#include <corsika/modules/switch_process/SwitchProcess.hpp>
 
 #include <catch2/catch.hpp>
 
diff --git a/tests/modules/testTrackingLine.cpp b/tests/modules/testTrackingLine.cpp
index 0885e9fac1a6f28bcc177a6118f424443f8ef268..70bfe8dd0f01411591569b94f30beee6d7ac5d3d 100644
--- a/tests/modules/testTrackingLine.cpp
+++ b/tests/modules/testTrackingLine.cpp
@@ -1,14 +1,12 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
-#include <corsika/modules/tracking_line/TrackingLine.hpp>
+#include <corsika/modules/TrackingLine.hpp>
 
 #include <testTrackingLineStack.hpp> // test-build, and include file is obtained from CMAKE_CURRENT_SOURCE_DIR
 
diff --git a/tests/modules/testTrackingLineStack.hpp b/tests/modules/testTrackingLineStack.hpp
index 6e6ed16eb1668c773471ea3c4f999735fb7c938b..ee9375c23a4198847c8ec2604169548154305bdc 100644
--- a/tests/modules/testTrackingLineStack.hpp
+++ b/tests/modules/testTrackingLineStack.hpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/modules/testUrQMD.cpp b/tests/modules/testUrQMD.cpp
index a76025124840dca8f18186b906e292e9b13c67ef..cb737f0eaf9e5e06542c85f6114adecf636f0289 100644
--- a/tests/modules/testUrQMD.cpp
+++ b/tests/modules/testUrQMD.cpp
@@ -1,26 +1,22 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
  * the license.
  */
 
-#include <corsika/framework/random/RNGManager.hpp>
 #include <corsika/modules/urqmd/UrQMD.hpp>
 
+#include <corsika/framework/core/ParticleProperties.hpp>
+#include <corsika/framework/core/PhysicalConstants.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/RootCoordinateSystem.hpp>
 #include <corsika/framework/geometry/Vector.hpp>
-
-#include <corsika/framework/core/PhysicalConstants.hpp>
-#include <corsika/framework/core/PhysicalUnits.hpp>
-
+#include <corsika/framework/random/RNGManager.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 
-#include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/setup/SetupStack.hpp>
 #include <corsika/setup/SetupTrajectory.hpp>
 
@@ -35,7 +31,6 @@
 
 using namespace corsika;
 using namespace corsika::urqmd;
-using namespace corsika::units::si;
 
 template <typename TStackView>
 auto sumCharge(TStackView const& view) {
@@ -82,17 +77,16 @@ template <typename TNodeType>
 auto setupStack(int vA, int vZ, HEPEnergyType vMomentum, TNodeType* vNodePtr,
                 corsika::CoordinateSystem const& cs) {
   auto stack = std::make_unique<setup::Stack>();
-  auto constexpr mN = corsika::units::constants::nucleonMass;
+  auto constexpr mN = corsika::constants::nucleonMass;
 
   corsika::Point const origin(cs, {0_m, 0_m, 0_m});
   corsika::MomentumVector const pLab(cs, {vMomentum, 0_GeV, 0_GeV});
 
-  HEPEnergyType const E0 =
-      sqrt(units::si::detail::static_pow<2>(mN * vA) + pLab.squaredNorm());
+  HEPEnergyType const E0 = sqrt(static_pow<2>(mN * vA) + pLab.squaredNorm());
   auto particle = stack->AddParticle(
-      std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                 corsika::Point, units::si::TimeType, unsigned short, unsigned short>{
-          corsika::Code::Nucleus, E0, pLab, origin, 0_ns, vA, vZ});
+      std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector, corsika::Point,
+                 TimeType, unsigned short, unsigned short>{corsika::Code::Nucleus, E0,
+                                                           pLab, origin, 0_ns, vA, vZ});
 
   particle.SetNode(vNodePtr);
   return std::make_tuple(
@@ -109,12 +103,10 @@ auto setupStack(corsika::Code vProjectileType, HEPEnergyType vMomentum,
   corsika::MomentumVector const pLab(cs, {vMomentum, 0_GeV, 0_GeV});
 
   HEPEnergyType const E0 =
-      sqrt(units::si::detail::static_pow<2>(corsika::GetMass(vProjectileType)) +
-           pLab.squaredNorm());
+      sqrt(static_pow<2>(corsika::GetMass(vProjectileType)) + pLab.squaredNorm());
   auto particle = stack->AddParticle(
-      std::tuple<corsika::Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                 corsika::Point, units::si::TimeType>{vProjectileType, E0, pLab, origin,
-                                                      0_ns});
+      std::tuple<corsika::Code, HEPEnergyType, corsika::MomentumVector, corsika::Point,
+                 TimeType>{vProjectileType, E0, pLab, origin, 0_ns});
 
   particle.SetNode(vNodePtr);
   return std::make_tuple(
@@ -137,6 +129,7 @@ TEST_CASE("UrQMD") {
   SECTION("cross sections") {
     auto [env, csPtr, nodePtr] = setupEnvironment(corsika::Code::Unknown);
     auto const& cs = *csPtr;
+    { [[maybe_unused]] auto const& env_dummy = env; }
 
     corsika::Code validProjectileCodes[] = {
         corsika::Code::PiPlus,  corsika::Code::PiMinus, corsika::Code::Proton,
@@ -162,8 +155,10 @@ TEST_CASE("UrQMD") {
 
   SECTION("nucleon projectile") {
     auto [env, csPtr, nodePtr] = setupEnvironment(corsika::Code::Oxygen);
+    { [[maybe_unused]] auto const& env_dummy = env; }
     unsigned short constexpr A = 14, Z = 7;
     auto [stackPtr, secViewPtr] = setupStack(A, Z, 400_GeV, nodePtr, *csPtr);
+    { [[maybe_unused]] auto const& dummy = stackPtr; }
 
     // must be assigned to variable, cannot be used as rvalue?!
     auto projectile = secViewPtr->GetProjectile();
@@ -181,8 +176,10 @@ TEST_CASE("UrQMD") {
 
   SECTION("\"special\" projectile") {
     auto [env, csPtr, nodePtr] = setupEnvironment(corsika::Code::Oxygen);
+    { [[maybe_unused]] auto const& env_dummy = env; }
     auto [stackPtr, secViewPtr] =
         setupStack(corsika::Code::PiPlus, 400_GeV, nodePtr, *csPtr);
+    { [[maybe_unused]] auto const& dummy = stackPtr; }
 
     // must be assigned to variable, cannot be used as rvalue?!
     auto projectile = secViewPtr->GetProjectile();
@@ -202,8 +199,10 @@ TEST_CASE("UrQMD") {
 
   SECTION("K0Long projectile") {
     auto [env, csPtr, nodePtr] = setupEnvironment(corsika::Code::Oxygen);
+    { [[maybe_unused]] auto const& env_dummy = env; }
     auto [stackPtr, secViewPtr] =
         setupStack(corsika::Code::K0Long, 400_GeV, nodePtr, *csPtr);
+    { [[maybe_unused]] auto const& dummy = stackPtr; }
 
     // must be assigned to variable, cannot be used as rvalue?!
     auto projectile = secViewPtr->GetProjectile();
diff --git a/tests/stack/CMakeLists.txt b/tests/stack/CMakeLists.txt
index 70045765c7e2cfdca38aca805c472e8363a465e0..26c8fb911db05184b5d039be94d6a5ea8f616e5f 100644
--- a/tests/stack/CMakeLists.txt
+++ b/tests/stack/CMakeLists.txt
@@ -1,28 +1,9 @@
-
-set (sources
+set (test_stack_sources
   TestMain.cpp
   testSuperStupidStack.cpp
   testNuclearStackExtension.cpp
+  testGeometryNodeStackExtension.cpp
+  testDummyStack.cpp
   )
 
-
-add_executable (testStack ${sources})
-
-target_link_libraries (testStack CORSIKA8 Catch2)
-
-target_compile_options (testStack PRIVATE -g) # do not skip asserts
-
-target_include_directories (testStack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-
-file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/test_outputs/)
-
-if (CORSIKA_SANITIZERS_ENABLED)
-  # -O1 is suggested in clang docs to get reasonable performance
-  target_compile_options (${name} PRIVATE -O1 -fno-omit-frame-pointer -fsanitize=${sanitize} -fno-sanitize-recover=all)
-  set_target_properties (${name} PROPERTIES LINK_FLAGS "-fsanitize=${sanitize}")
-endif ()
-
-add_test (
-  NAME testStack
-  COMMAND testStack -o ${PROJECT_BINARY_DIR}/test_outputs/junit-${name}.xml -s -r junit
-  )
+CORSIKA_ADD_TEST (testStack SOURCES ${test_stack_sources})
diff --git a/tests/stack/TestMain.cpp b/tests/stack/TestMain.cpp
index da6f2c3f1a0f72b5af0d49771b908c57e6b51d3b..51532584b8e03b35d79301543ac8f80b598ba544 100644
--- a/tests/stack/TestMain.cpp
+++ b/tests/stack/TestMain.cpp
@@ -1,7 +1,5 @@
 /*
- * (c) Copyright 2019 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
diff --git a/tests/stack/testDummyStack.cpp b/tests/stack/testDummyStack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..41a5731589d0909405f11de46188784eb9fa710b
--- /dev/null
+++ b/tests/stack/testDummyStack.cpp
@@ -0,0 +1,41 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <corsika/stack/dummy/DummyStack.h>
+
+using namespace corsika;
+using namespace corsika::stack;
+
+#include <catch2/catch.hpp>
+
+#include <tuple>
+
+TEST_CASE("DummyStack", "[stack]") {
+
+  using TestStack = dummy::DummyStack;
+
+  dummy::NoData noData;
+
+  SECTION("write node") {
+
+    TestStack s;
+    s.AddParticle(std::tuple<dummy::NoData>{noData});
+    CHECK(s.getEntries() == 1);
+  }
+
+  SECTION("stack fill and cleanup") {
+
+    TestStack s;
+    // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
+    for (int i = 0; i < 99; ++i) { s.AddParticle(std::tuple<dummy::NoData>{noData}); }
+
+    CHECK(s.getEntries() == 99);
+    for (int i = 0; i < 99; ++i) s.GetNextParticle().Delete();
+    CHECK(s.getEntries() == 0);
+  }
+}
diff --git a/tests/stack/testGeometryNodeStackExtension.cpp b/tests/stack/testGeometryNodeStackExtension.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b566c2c8ebed2848b243a28bd0b21b28219fcfc1
--- /dev/null
+++ b/tests/stack/testGeometryNodeStackExtension.cpp
@@ -0,0 +1,90 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <corsika/stack/CombinedStack.h>
+#include <corsika/stack/dummy/DummyStack.h>
+#include <corsika/stack/node/GeometryNodeStackExtension.h>
+
+using namespace corsika;
+using namespace corsika::stack;
+
+#include <catch2/catch.hpp>
+
+#include <iostream>
+using namespace std;
+
+// this is our dummy environment, it only knows its trivial BaseNodeType
+class DummyEnv {
+public:
+  typedef int BaseNodeType;
+};
+
+// the GeometryNode stack needs to know the type of geometry-nodes from the DummyEnv:
+template <typename TStackIter>
+using DummyGeometryDataInterface =
+    typename corsika::stack::node::MakeGeometryDataInterface<TStackIter, DummyEnv>::type;
+
+// combine dummy stack with geometry information for tracking
+template <typename TStackIter>
+using StackWithGeometryInterface =
+    corsika::stack::CombinedParticleInterface<dummy::DummyStack::MPIType,
+                                              DummyGeometryDataInterface, TStackIter>;
+
+using TestStack =
+    corsika::stack::CombinedStack<typename stack::dummy::DummyStack::StackImpl,
+                                  stack::node::GeometryData<DummyEnv>,
+                                  StackWithGeometryInterface>;
+
+TEST_CASE("GeometryNodeStackExtension", "[stack]") {
+
+  dummy::NoData noData;
+
+  SECTION("write node") {
+
+    const int data = 5;
+
+    TestStack s;
+    s.AddParticle(std::make_tuple(noData), std::tuple<const int*>{&data});
+
+    CHECK(s.getEntries() == 1);
+  }
+
+  SECTION("write/read node") {
+    const int data = 15;
+
+    TestStack s;
+    auto p = s.AddParticle(std::make_tuple(noData));
+    p.SetNode(&data);
+    CHECK(s.getEntries() == 1);
+
+    const auto pout = s.GetNextParticle();
+    CHECK(*(pout.GetNode()) == 15);
+  }
+
+  SECTION("stack fill and cleanup") {
+
+    const int data = 16;
+
+    TestStack s;
+    // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
+    for (int i = 0; i < 99; ++i) {
+      auto p = s.AddParticle(std::tuple<dummy::NoData>{noData});
+      p.SetNode(&data);
+    }
+
+    CHECK(s.getEntries() == 99);
+    double v = 0;
+    for (int i = 0; i < 99; ++i) {
+      auto p = s.GetNextParticle();
+      v += *(p.GetNode());
+      p.Delete();
+    }
+    CHECK(v == 99 * data);
+    CHECK(s.getEntries() == 0);
+  }
+}
diff --git a/tests/stack/testNuclearStackExtension.cpp b/tests/stack/testNuclearStackExtension.cpp
index d38fa04f10c75eff12a052f67929cdffbc4bae1e..72017c91a05c70d9c062fd72c20f0ff31cc4e246 100644
--- a/tests/stack/testNuclearStackExtension.cpp
+++ b/tests/stack/testNuclearStackExtension.cpp
@@ -6,99 +6,87 @@
  * the license.
  */
 
-#include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/geometry/RootCoordinateSystem.hpp>
-#include <corsika/stack/NuclearStackExtension.hpp>
-#include <corsika/stack/SuperStupidStack.hpp>
+#include <corsika/geometry/RootCoordinateSystem.h>
+#include <corsika/stack/nuclear_extension/NuclearStackExtension.h>
+#include <corsika/units/PhysicalUnits.h>
 
 using namespace corsika;
-using namespace corsika::nuclear_extension;
+using namespace corsika::stack::nuclear_extension;
+using namespace corsika::geometry;
 using namespace corsika::units::si;
 
 #include <catch2/catch.hpp>
 
-// this is an auxiliary help typedef, which I don't know how to put
-// into NuclearStackExtension.h where it belongs...
-template <typename StackIter>
-using ExtendedParticleInterfaceType =
-    corsika::nuclear_extension::NuclearParticleInterface<
-        corsika::super_stupid::SuperStupidStack::template PIType, StackIter>;
-
-using ExtStack = NuclearStackExtension<corsika::super_stupid::SuperStupidStack,
-                                       ExtendedParticleInterfaceType>;
-
 #include <iostream>
 using namespace std;
 
 TEST_CASE("NuclearStackExtension", "[stack]") {
 
-  CoordinateSystem& dummyCS =
-      RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
+  geometry::CoordinateSystem& dummyCS =
+      geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
 
   SECTION("write non nucleus") {
-    NuclearStackExtension<corsika::super_stupid::SuperStupidStack,
+    NuclearStackExtension<corsika::stack::super_stupid::SuperStupidStack,
                           ExtendedParticleInterfaceType>
         s;
-    s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                             Point, units::si::TimeType>{
-        Code::Electron, 1.5_GeV, corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
-    REQUIRE(s.GetSize() == 1);
+    s.AddParticle(
+        std::make_tuple(particles::Code::Electron, 1.5_GeV,
+                        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
+    CHECK(s.getEntries() == 1);
   }
 
   SECTION("write nucleus") {
-    NuclearStackExtension<corsika::super_stupid::SuperStupidStack,
+    NuclearStackExtension<corsika::stack::super_stupid::SuperStupidStack,
                           ExtendedParticleInterfaceType>
         s;
-    s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                             Point, units::si::TimeType, unsigned short, unsigned short>{
-        Code::Nucleus, 1.5_GeV, corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 10});
-    REQUIRE(s.GetSize() == 1);
+    s.AddParticle(std::make_tuple(
+        particles::Code::Nucleus, 1.5_GeV,
+        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 10));
+    CHECK(s.getEntries() == 1);
   }
 
   SECTION("write invalid nucleus") {
-    ExtStack s;
-    REQUIRE_THROWS(s.AddParticle(
-        std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector, Point,
-                   units::si::TimeType, unsigned short, unsigned short>{
-            Code::Nucleus, 1.5_GeV,
-            corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 0, 0}));
+    ParticleDataStack s;
+    CHECK_THROWS(s.AddParticle(
+        std::make_tuple(particles::Code::Nucleus, 1.5_GeV,
+                        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 0, 0)));
   }
 
   SECTION("read non nucleus") {
-    ExtStack s;
-    s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                             Point, units::si::TimeType>{
-        Code::Electron, 1.5_GeV, corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
+    ParticleDataStack s;
+    s.AddParticle(
+        std::make_tuple(particles::Code::Electron, 1.5_GeV,
+                        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
     const auto pout = s.GetNextParticle();
-    REQUIRE(pout.GetPID() == Code::Electron);
-    REQUIRE(pout.GetEnergy() == 1.5_GeV);
-    REQUIRE(pout.GetTime() == 100_s);
+    CHECK(pout.GetPID() == particles::Code::Electron);
+    CHECK(pout.GetEnergy() == 1.5_GeV);
+    CHECK(pout.GetTime() == 100_s);
   }
 
   SECTION("read nucleus") {
-    ExtStack s;
-    s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                             Point, units::si::TimeType, unsigned short, unsigned short>{
-        Code::Nucleus, 1.5_GeV, corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 9});
+    ParticleDataStack s;
+    s.AddParticle(
+        std::make_tuple(particles::Code::Nucleus, 1.5_GeV,
+                        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 9));
     const auto pout = s.GetNextParticle();
-    REQUIRE(pout.GetPID() == Code::Nucleus);
-    REQUIRE(pout.GetEnergy() == 1.5_GeV);
-    REQUIRE(pout.GetTime() == 100_s);
-    REQUIRE(pout.GetNuclearA() == 10);
-    REQUIRE(pout.GetNuclearZ() == 9);
+    CHECK(pout.GetPID() == particles::Code::Nucleus);
+    CHECK(pout.GetEnergy() == 1.5_GeV);
+    CHECK(pout.GetTime() == 100_s);
+    CHECK(pout.GetNuclearA() == 10);
+    CHECK(pout.GetNuclearZ() == 9);
   }
 
   SECTION("read invalid nucleus") {
-    ExtStack s;
-    s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                             Point, units::si::TimeType>{
-        Code::Electron, 1.5_GeV, corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
+    ParticleDataStack s;
+    s.AddParticle(
+        std::make_tuple(particles::Code::Electron, 1.5_GeV,
+                        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
     const auto pout = s.GetNextParticle();
     CHECK_THROWS(pout.GetNuclearA());
     CHECK_THROWS(pout.GetNuclearZ());
@@ -110,18 +98,15 @@ TEST_CASE("NuclearStackExtension", "[stack]") {
     // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
     for (int i = 0; i < 99; ++i) {
       if ((i + 1) % 10 == 0) {
-        s.AddParticle(
-            std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector, Point,
-                       units::si::TimeType, unsigned short, unsigned short>{
-                Code::Nucleus, 1.5_GeV,
-                corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-                Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i / 2});
+        s.AddParticle(std::make_tuple(
+            particles::Code::Nucleus, 1.5_GeV,
+            corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i / 2));
       } else {
-        s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                                 Point, units::si::TimeType>{
-            Code::Electron, 1.5_GeV,
-            corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
+        s.AddParticle(std::make_tuple(
+            particles::Code::Electron, 1.5_GeV,
+            corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
       }
     }
 
@@ -137,18 +122,15 @@ TEST_CASE("NuclearStackExtension", "[stack]") {
     // i=9, 19, 29, etc. are nuclei
     for (int i = 0; i < 99; ++i) {
       if ((i + 1) % 10 == 0) {
-        s.AddParticle(
-            std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector, Point,
-                       units::si::TimeType, unsigned short, unsigned short>{
-                Code::Nucleus, i * 15_GeV,
-                corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-                Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i / 2});
+        s.AddParticle(std::make_tuple(
+            particles::Code::Nucleus, i * 15_GeV,
+            corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i / 2));
       } else {
-        s.AddParticle(std::tuple<Code, units::si::HEPEnergyType, corsika::MomentumVector,
-                                 Point, units::si::TimeType>{
-            Code::Electron, i * 1.5_GeV,
-            corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
+        s.AddParticle(std::make_tuple(
+            particles::Code::Electron, i * 1.5_GeV,
+            corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
       }
     }
 
@@ -158,17 +140,17 @@ TEST_CASE("NuclearStackExtension", "[stack]") {
       const auto& p9 = s.cbegin() + 9;
       const auto& p10 = s.cbegin() + 10;
 
-      REQUIRE(p9.GetPID() == Code::Nucleus);
-      REQUIRE(p9.GetEnergy() == 9 * 15_GeV);
-      REQUIRE(p9.GetTime() == 100_s);
-      REQUIRE(p9.GetNuclearA() == 9);
-      REQUIRE(p9.GetNuclearZ() == 9 / 2);
-
-      REQUIRE(p10.GetPID() == Code::Nucleus);
-      REQUIRE(p10.GetEnergy() == 9 * 15_GeV);
-      REQUIRE(p10.GetTime() == 100_s);
-      REQUIRE(p10.GetNuclearA() == 9);
-      REQUIRE(p10.GetNuclearZ() == 9 / 2);
+      CHECK(p9.GetPID() == particles::Code::Nucleus);
+      CHECK(p9.GetEnergy() == 9 * 15_GeV);
+      CHECK(p9.GetTime() == 100_s);
+      CHECK(p9.GetNuclearA() == 9);
+      CHECK(p9.GetNuclearZ() == 9 / 2);
+
+      CHECK(p10.GetPID() == particles::Code::Nucleus);
+      CHECK(p10.GetEnergy() == 9 * 15_GeV);
+      CHECK(p10.GetTime() == 100_s);
+      CHECK(p10.GetNuclearA() == 9);
+      CHECK(p10.GetNuclearZ() == 9 / 2);
     }
 
     // copy
@@ -177,13 +159,28 @@ TEST_CASE("NuclearStackExtension", "[stack]") {
       const auto& p93 = s.cbegin() + 93;
       const auto& p9 = s.cbegin() + 9;
 
-      REQUIRE(p9.GetPID() == Code::Electron);
-      REQUIRE(p9.GetEnergy() == 93 * 1.5_GeV);
-      REQUIRE(p9.GetTime() == 100_s);
+      CHECK(p9.GetPID() == particles::Code::Electron);
+      CHECK(p9.GetEnergy() == 93 * 1.5_GeV);
+      CHECK(p9.GetTime() == 100_s);
+
+      CHECK(p93.GetPID() == particles::Code::Electron);
+      CHECK(p93.GetEnergy() == 93 * 1.5_GeV);
+      CHECK(p93.GetTime() == 100_s);
+    }
+
+    // copy
+    {
+      s.Copy(s.begin() + 89, s.begin() + 79); // nuclei to nuclei
+      const auto& p89 = s.cbegin() + 89;
+      const auto& p79 = s.cbegin() + 79;
+
+      CHECK(p89.GetPID() == particles::Code::Nucleus);
+      CHECK(p89.GetEnergy() == 89 * 15_GeV);
+      CHECK(p89.GetTime() == 100_s);
 
-      REQUIRE(p93.GetPID() == Code::Electron);
-      REQUIRE(p93.GetEnergy() == 93 * 1.5_GeV);
-      REQUIRE(p93.GetTime() == 100_s);
+      CHECK(p79.GetPID() == particles::Code::Nucleus);
+      CHECK(p79.GetEnergy() == 89 * 15_GeV);
+      CHECK(p79.GetTime() == 100_s);
     }
 
     // swap
@@ -192,15 +189,15 @@ TEST_CASE("NuclearStackExtension", "[stack]") {
       const auto& p11 = s.cbegin() + 11; // now: nucleus
       const auto& p10 = s.cbegin() + 10; // now: electron
 
-      REQUIRE(p11.GetPID() == Code::Nucleus);
-      REQUIRE(p11.GetEnergy() == 9 * 15_GeV);
-      REQUIRE(p11.GetTime() == 100_s);
-      REQUIRE(p11.GetNuclearA() == 9);
-      REQUIRE(p11.GetNuclearZ() == 9 / 2);
+      CHECK(p11.GetPID() == particles::Code::Nucleus);
+      CHECK(p11.GetEnergy() == 9 * 15_GeV);
+      CHECK(p11.GetTime() == 100_s);
+      CHECK(p11.GetNuclearA() == 9);
+      CHECK(p11.GetNuclearZ() == 9 / 2);
 
-      REQUIRE(p10.GetPID() == Code::Electron);
-      REQUIRE(p10.GetEnergy() == 11 * 1.5_GeV);
-      REQUIRE(p10.GetTime() == 100_s);
+      CHECK(p10.GetPID() == particles::Code::Electron);
+      CHECK(p10.GetEnergy() == 11 * 1.5_GeV);
+      CHECK(p10.GetTime() == 100_s);
     }
 
     // swap two nuclei
@@ -209,17 +206,17 @@ TEST_CASE("NuclearStackExtension", "[stack]") {
       const auto& p29 = s.cbegin() + 29;
       const auto& p59 = s.cbegin() + 59;
 
-      REQUIRE(p29.GetPID() == Code::Nucleus);
-      REQUIRE(p29.GetEnergy() == 59 * 15_GeV);
-      REQUIRE(p29.GetTime() == 100_s);
-      REQUIRE(p29.GetNuclearA() == 59);
-      REQUIRE(p29.GetNuclearZ() == 59 / 2);
-
-      REQUIRE(p59.GetPID() == Code::Nucleus);
-      REQUIRE(p59.GetEnergy() == 29 * 15_GeV);
-      REQUIRE(p59.GetTime() == 100_s);
-      REQUIRE(p59.GetNuclearA() == 29);
-      REQUIRE(p59.GetNuclearZ() == 29 / 2);
+      CHECK(p29.GetPID() == particles::Code::Nucleus);
+      CHECK(p29.GetEnergy() == 59 * 15_GeV);
+      CHECK(p29.GetTime() == 100_s);
+      CHECK(p29.GetNuclearA() == 59);
+      CHECK(p29.GetNuclearZ() == 59 / 2);
+
+      CHECK(p59.GetPID() == particles::Code::Nucleus);
+      CHECK(p59.GetEnergy() == 29 * 15_GeV);
+      CHECK(p59.GetTime() == 100_s);
+      CHECK(p59.GetNuclearA() == 29);
+      CHECK(p59.GetNuclearZ() == 29 / 2);
     }
 
     for (int i = 0; i < 99; ++i) s.last().Delete();
diff --git a/tests/stack/testSuperStupidStack.cpp b/tests/stack/testSuperStupidStack.cpp
index 6ff35b13814c51f76402ad597a8c59068a94ac4c..a9f4fadc90d9d21125a92173b13b652e5aa7af90 100644
--- a/tests/stack/testSuperStupidStack.cpp
+++ b/tests/stack/testSuperStupidStack.cpp
@@ -6,57 +6,52 @@
  * the license.
  */
 
-#include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/geometry/RootCoordinateSystem.hpp>
-#include <corsika/stack/SuperStupidStack.hpp>
+#define protected public // to also test the internal state of objects
 
-using namespace corsika;
+#include <corsika/geometry/RootCoordinateSystem.h>
+#include <corsika/stack/super_stupid/SuperStupidStack.h>
+#include <corsika/units/PhysicalUnits.h>
+
+using namespace corsika::geometry;
 using namespace corsika::units::si;
 
 #include <catch2/catch.hpp>
 
 using namespace corsika;
-using namespace corsika::super_stupid;
+using namespace corsika::stack::super_stupid;
 
 using namespace std;
 
 TEST_CASE("SuperStupidStack", "[stack]") {
 
-  CoordinateSystem& dummyCS =
-      RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
+  geometry::CoordinateSystem& dummyCS =
+      geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
 
   SECTION("read+write") {
 
     SuperStupidStack s;
     s.AddParticle(
-        std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                   corsika::MomentumVector, corsika::Point, corsika::units::si::TimeType>{
-            Code::Electron, 1.5_GeV,
-            corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-            Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
+        std::make_tuple(particles::Code::Electron, 1.5_GeV,
+                        corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                        Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
 
     // read
     CHECK(s.getEntries() == 1);
     CHECK(s.getSize() == 1);
     auto pout = s.GetNextParticle();
-    REQUIRE(pout.GetPID() == Code::Electron);
-    REQUIRE(pout.GetEnergy() == 1.5_GeV);
-    // REQUIRE(pout.GetMomentum() == stack::MomentumVector(dummyCS, {1_GeV,
-    // 1_GeV, 1_GeV})); REQUIRE(pout.GetPosition() == Point(dummyCS, {1 * meter, 1 *
-    // meter, 1 * meter}));
-    REQUIRE(pout.GetTime() == 100_s);
+    CHECK(pout.GetPID() == particles::Code::Electron);
+    CHECK(pout.GetEnergy() == 1.5_GeV);
+    CHECK(pout.GetTime() == 100_s);
   }
 
   SECTION("write+delete") {
 
     SuperStupidStack s;
     for (int i = 0; i < 99; ++i)
-      s.AddParticle(std::tuple<corsika::Code, corsika::units::si::HEPEnergyType,
-                               corsika::MomentumVector, corsika::Point,
-                               corsika::units::si::TimeType>{
-          Code::Electron, 1.5_GeV,
-          corsika::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
-          Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
+      s.AddParticle(
+          std::make_tuple(particles::Code::Electron, 1.5_GeV,
+                          corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
+                          Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s));
 
     CHECK(s.getSize() == 99);