initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d9baec9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/build*
+*.pem
+*.crt
+*.key
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..56f2c2a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,68 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+
+cmake_policy(SET CMP0054 OLD)
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
+
+message("${CMAKE_MODULE_PATH}")
+
+#set(HUNTER_ROOT /home/ed/hunter)
+SET(HUNTER_STATUS_DEBUG ON)
+include("cmake/HunterGate.cmake")
+
+HunterGate(
+    URL "https://github.com/ruslo/hunter/archive/v0.16.31.tar.gz"
+    SHA1 "8fcc0a2d6206e1f2c6fc011e3e694e388d030b53"
+)
+
+option(BUILD_FOR_EMBEDDED "Build for device target" ON)
+
+project(bmc-webserver CXX C)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
+    message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (usually called build) and run CMake from there. You may need to remove CMakeCache.txt." )
+endif()
+
+# general
+option(BUILD_SHARED_LIBS "Build Pion as shared library" OFF)
+option(BUILD_UT "Enable Unit test" OFF)
+
+# Boost
+add_definitions(-DBOOST_ALL_NO_LIB)
+set(Boost_USE_STATIC_LIBS ON)
+hunter_add_package(Boost COMPONENTS system thread regex)
+find_package(Boost COMPONENTS system thread regex REQUIRED)
+
+#Openssl
+hunter_add_package(OpenSSL)
+find_package(OpenSSL REQUIRED)
+if (NOT OPENSSL_FOUND)
+    message(FATAL_ERROR "Could not find OpenSSL")
+endif()
+include_directories(${OPENSSL_INCLUDE_DIR})
+
+# Crow
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/crow/include)
+
+#g3 logging
+set(ADD_FATAL_EXAMPLE OFF)
+add_subdirectory(g3log)
+include_directories(g3log/src)
+
+# Debug sanitizers
+find_package(Sanitizers)
+
+# Executable
+add_executable(example ${CMAKE_CURRENT_SOURCE_DIR}/src/example.cpp)
+#target_link_libraries(example crow)
+target_link_libraries(example Boost::boost Boost::system)
+target_link_libraries(example ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(example OpenSSL::SSL OpenSSL::Crypto)
+target_link_libraries(example g3logger)
+
+
diff --git a/cmake/FindASan.cmake b/cmake/FindASan.cmake
new file mode 100644
index 0000000..fcebb43
--- /dev/null
+++ b/cmake/FindASan.cmake
@@ -0,0 +1,59 @@
+# The MIT License (MIT)
+#
+# Copyright (c)
+#   2013 Matthew Arsenault
+#   2015-2016 RWTH Aachen University, Federal Republic of Germany
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off)
+
+set(FLAG_CANDIDATES
+    # Clang 3.2+ use this version. The no-omit-frame-pointer option is optional.
+    "-g -fsanitize=address -fno-omit-frame-pointer"
+    "-g -fsanitize=address"
+
+    # Older deprecated flag for ASan
+    "-g -faddress-sanitizer"
+)
+
+
+if (SANITIZE_ADDRESS AND (SANITIZE_THREAD OR SANITIZE_MEMORY))
+    message(FATAL_ERROR "AddressSanitizer is not compatible with "
+        "ThreadSanitizer or MemorySanitizer.")
+endif ()
+
+
+include(sanitize-helpers)
+
+if (SANITIZE_ADDRESS)
+    sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer"
+        "ASan")
+
+    find_program(ASan_WRAPPER "asan-wrapper" PATHS ${CMAKE_MODULE_PATH})
+	mark_as_advanced(ASan_WRAPPER)
+endif ()
+
+function (add_sanitize_address TARGET)
+    if (NOT SANITIZE_ADDRESS)
+        return()
+    endif ()
+
+    saitizer_add_flags(${TARGET} "AddressSanitizer" "ASan")
+endfunction ()
diff --git a/cmake/FindMSan.cmake b/cmake/FindMSan.cmake
new file mode 100644
index 0000000..3b0a4ad
--- /dev/null
+++ b/cmake/FindMSan.cmake
@@ -0,0 +1,57 @@
+# The MIT License (MIT)
+#
+# Copyright (c)
+#   2013 Matthew Arsenault
+#   2015-2016 RWTH Aachen University, Federal Republic of Germany
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+option(SANITIZE_MEMORY "Enable MemorySanitizer for sanitized targets." Off)
+
+set(FLAG_CANDIDATES
+    "-g -fsanitize=memory"
+)
+
+
+include(sanitize-helpers)
+
+if (SANITIZE_MEMORY)
+    if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+        message(WARNING "MemorySanitizer disabled for target ${TARGET} because "
+            "MemorySanitizer is supported for Linux systems only.")
+        set(SANITIZE_MEMORY Off CACHE BOOL
+            "Enable MemorySanitizer for sanitized targets." FORCE)
+    elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+        message(WARNING "MemorySanitizer disabled for target ${TARGET} because "
+            "MemorySanitizer is supported for 64bit systems only.")
+        set(SANITIZE_MEMORY Off CACHE BOOL
+            "Enable MemorySanitizer for sanitized targets." FORCE)
+    else ()
+        sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "MemorySanitizer"
+            "MSan")
+    endif ()
+endif ()
+
+function (add_sanitize_memory TARGET)
+    if (NOT SANITIZE_MEMORY)
+        return()
+    endif ()
+
+    saitizer_add_flags(${TARGET} "MemorySanitizer" "MSan")
+endfunction ()
diff --git a/cmake/FindSanitizers.cmake b/cmake/FindSanitizers.cmake
new file mode 100644
index 0000000..71cda38
--- /dev/null
+++ b/cmake/FindSanitizers.cmake
@@ -0,0 +1,87 @@
+# The MIT License (MIT)
+#
+# Copyright (c)
+#   2013 Matthew Arsenault
+#   2015-2016 RWTH Aachen University, Federal Republic of Germany
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# If any of the used compiler is a GNU compiler, add a second option to static
+# link against the sanitizers.
+option(SANITIZE_LINK_STATIC "Try to link static against sanitizers." Off)
+
+
+
+
+set(FIND_QUIETLY_FLAG "")
+if (DEFINED Sanitizers_FIND_QUIETLY)
+    set(FIND_QUIETLY_FLAG "QUIET")
+endif ()
+
+find_package(ASan ${FIND_QUIETLY_FLAG})
+find_package(TSan ${FIND_QUIETLY_FLAG})
+find_package(MSan ${FIND_QUIETLY_FLAG})
+find_package(UBSan ${FIND_QUIETLY_FLAG})
+
+
+
+
+function(sanitizer_add_blacklist_file FILE)
+    if(NOT IS_ABSOLUTE ${FILE})
+        set(FILE "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}")
+    endif()
+    get_filename_component(FILE "${FILE}" REALPATH)
+
+    sanitizer_check_compiler_flags("-fsanitize-blacklist=${FILE}"
+        "SanitizerBlacklist" "SanBlist")
+endfunction()
+
+function(add_sanitizers ...)
+    # If no sanitizer is enabled, return immediately.
+    if (NOT (SANITZE_ADDRESS OR SANITIZE_MEMORY OR SANITIZE_THREAD OR
+        SANITIZE_UNDEFINED))
+        return()
+    endif ()
+
+    foreach (TARGET ${ARGV})
+        # Check if this target will be compiled by exactly one compiler. Other-
+        # wise sanitizers can't be used and a warning should be printed once.
+        sanitizer_target_compilers(${TARGET} TARGET_COMPILER)
+        list(LENGTH TARGET_COMPILER NUM_COMPILERS)
+        if (NUM_COMPILERS GREATER 1)
+            message(WARNING "Can't use any sanitizers for target ${TARGET}, "
+                    "because it will be compiled by incompatible compilers. "
+                    "Target will be compiled without sanitzers.")
+            return()
+
+        # If the target is compiled by no known compiler, ignore it.
+        elseif (NUM_COMPILERS EQUAL 0)
+            message(WARNING "Can't use any sanitizers for target ${TARGET}, "
+                    "because it uses an unknown compiler. Target will be "
+                    "compiled without sanitzers.")
+            return()
+        endif ()
+
+        # Add sanitizers for target.
+        add_sanitize_address(${TARGET})
+        add_sanitize_thread(${TARGET})
+        add_sanitize_memory(${TARGET})
+        add_sanitize_undefined(${TARGET})
+	endforeach ()
+endfunction(add_sanitizers)
diff --git a/cmake/FindTSan.cmake b/cmake/FindTSan.cmake
new file mode 100644
index 0000000..0e80f29
--- /dev/null
+++ b/cmake/FindTSan.cmake
@@ -0,0 +1,64 @@
+# The MIT License (MIT)
+#
+# Copyright (c)
+#   2013 Matthew Arsenault
+#   2015-2016 RWTH Aachen University, Federal Republic of Germany
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+option(SANITIZE_THREAD "Enable ThreadSanitizer for sanitized targets." Off)
+
+set(FLAG_CANDIDATES
+    "-g -fsanitize=thread"
+)
+
+
+# ThreadSanitizer is not compatible with MemorySanitizer.
+if (SANITIZE_THREAD AND SANITIZE_MEMORY)
+    message(FATAL_ERROR "ThreadSanitizer is not compatible with "
+        "MemorySanitizer.")
+endif ()
+
+
+include(sanitize-helpers)
+
+if (SANITIZE_THREAD)
+    if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+        message(WARNING "ThreadSanitizer disabled for target ${TARGET} because "
+            "ThreadSanitizer is supported for Linux systems only.")
+        set(SANITIZE_THREAD Off CACHE BOOL
+            "Enable ThreadSanitizer for sanitized targets." FORCE)
+    elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+        message(WARNING "ThreadSanitizer disabled for target ${TARGET} because "
+            "ThreadSanitizer is supported for 64bit systems only.")
+        set(SANITIZE_THREAD Off CACHE BOOL
+            "Enable ThreadSanitizer for sanitized targets." FORCE)
+    else ()
+        sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "ThreadSanitizer"
+            "TSan")
+    endif ()
+endif ()
+
+function (add_sanitize_thread TARGET)
+    if (NOT SANITIZE_THREAD)
+        return()
+    endif ()
+
+    saitizer_add_flags(${TARGET} "ThreadSanitizer" "TSan")
+endfunction ()
diff --git a/cmake/FindUBSan.cmake b/cmake/FindUBSan.cmake
new file mode 100644
index 0000000..6948674
--- /dev/null
+++ b/cmake/FindUBSan.cmake
@@ -0,0 +1,46 @@
+# The MIT License (MIT)
+#
+# Copyright (c)
+#   2013 Matthew Arsenault
+#   2015-2016 RWTH Aachen University, Federal Republic of Germany
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+option(SANITIZE_UNDEFINED
+    "Enable UndefinedBehaviorSanitizer for sanitized targets." Off)
+
+set(FLAG_CANDIDATES
+    "-g -fsanitize=undefined"
+)
+
+
+include(sanitize-helpers)
+
+if (SANITIZE_UNDEFINED)
+    sanitizer_check_compiler_flags("${FLAG_CANDIDATES}"
+        "UndefinedBehaviorSanitizer" "UBSan")
+endif ()
+
+function (add_sanitize_undefined TARGET)
+    if (NOT SANITIZE_UNDEFINED)
+        return()
+    endif ()
+
+    saitizer_add_flags(${TARGET} "UndefinedBehaviorSanitizer" "UBSan")
+endfunction ()
diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake
new file mode 100644
index 0000000..97f69cc
--- /dev/null
+++ b/cmake/HunterGate.cmake
@@ -0,0 +1,514 @@
+# Copyright (c) 2013-2015, Ruslan Baratov
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+#   list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This is a gate file to Hunter package manager.
+# Include this file using `include` command and add package you need, example:
+#
+#     cmake_minimum_required(VERSION 3.0)
+#
+#     include("cmake/HunterGate.cmake")
+#     HunterGate(
+#         URL "https://github.com/path/to/hunter/archive.tar.gz"
+#         SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
+#     )
+#
+#     project(MyProject)
+#
+#     hunter_add_package(Foo)
+#     hunter_add_package(Boo COMPONENTS Bar Baz)
+#
+# Projects:
+#     * https://github.com/hunter-packages/gate/
+#     * https://github.com/ruslo/hunter
+
+option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
+if(HUNTER_ENABLED)
+  if(CMAKE_VERSION VERSION_LESS "3.0")
+    message(FATAL_ERROR "At least CMake version 3.0 required for hunter dependency management."
+      " Update CMake or set HUNTER_ENABLED to OFF.")
+  endif()
+endif()
+
+include(CMakeParseArguments) # cmake_parse_arguments
+
+option(HUNTER_STATUS_PRINT "Print working status" ON)
+option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
+
+set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
+
+function(hunter_gate_status_print)
+  foreach(print_message ${ARGV})
+    if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
+      message(STATUS "[hunter] ${print_message}")
+    endif()
+  endforeach()
+endfunction()
+
+function(hunter_gate_status_debug)
+  foreach(print_message ${ARGV})
+    if(HUNTER_STATUS_DEBUG)
+      string(TIMESTAMP timestamp)
+      message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
+    endif()
+  endforeach()
+endfunction()
+
+function(hunter_gate_wiki wiki_page)
+  message("------------------------------ WIKI -------------------------------")
+  message("    ${HUNTER_WIKI}/${wiki_page}")
+  message("-------------------------------------------------------------------")
+  message("")
+  message(FATAL_ERROR "")
+endfunction()
+
+function(hunter_gate_internal_error)
+  message("")
+  foreach(print_message ${ARGV})
+    message("[hunter ** INTERNAL **] ${print_message}")
+  endforeach()
+  message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("error.internal")
+endfunction()
+
+function(hunter_gate_fatal_error)
+  cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
+  string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
+  if(have_no_wiki)
+    hunter_gate_internal_error("Expected wiki")
+  endif()
+  message("")
+  foreach(x ${hunter_UNPARSED_ARGUMENTS})
+    message("[hunter ** FATAL ERROR **] ${x}")
+  endforeach()
+  message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("${hunter_WIKI}")
+endfunction()
+
+function(hunter_gate_user_error)
+  hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
+endfunction()
+
+function(hunter_gate_self root version sha1 result)
+  string(COMPARE EQUAL "${root}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("root is empty")
+  endif()
+
+  string(COMPARE EQUAL "${version}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("version is empty")
+  endif()
+
+  string(COMPARE EQUAL "${sha1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("sha1 is empty")
+  endif()
+
+  string(SUBSTRING "${sha1}" 0 7 archive_id)
+
+  if(EXISTS "${root}/cmake/Hunter")
+    set(hunter_self "${root}")
+  else()
+    set(
+        hunter_self
+        "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
+    )
+  endif()
+
+  set("${result}" "${hunter_self}" PARENT_SCOPE)
+endfunction()
+
+# Set HUNTER_GATE_ROOT cmake variable to suitable value.
+function(hunter_gate_detect_root)
+  # Check CMake variable
+  string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
+    return()
+  endif()
+
+  # Check environment variable
+  string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
+    return()
+  endif()
+
+  # Check HOME environment variable
+  string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
+  if(result)
+    set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
+    return()
+  endif()
+
+  # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
+  if(WIN32)
+    string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using SYSTEMDRIVE environment variable"
+      )
+      return()
+    endif()
+
+    string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using USERPROFILE environment variable"
+      )
+      return()
+    endif()
+  endif()
+
+  hunter_gate_fatal_error(
+      "Can't detect HUNTER_ROOT"
+      WIKI "error.detect.hunter.root"
+  )
+endfunction()
+
+macro(hunter_gate_lock dir)
+  if(NOT HUNTER_SKIP_LOCK)
+    if("${CMAKE_VERSION}" VERSION_LESS "3.2")
+      hunter_gate_fatal_error(
+          "Can't lock, upgrade to CMake 3.2 or use HUNTER_SKIP_LOCK"
+          WIKI "error.can.not.lock"
+      )
+    endif()
+    hunter_gate_status_debug("Locking directory: ${dir}")
+    file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
+    hunter_gate_status_debug("Lock done")
+  endif()
+endmacro()
+
+function(hunter_gate_download dir)
+  string(
+      COMPARE
+      NOTEQUAL
+      "$ENV{HUNTER_DISABLE_AUTOINSTALL}"
+      ""
+      disable_autoinstall
+  )
+  if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
+    hunter_gate_fatal_error(
+        "Hunter not found in '${dir}'"
+        "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
+        "Settings:"
+        "  HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
+        "  HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
+        WIKI "error.run.install"
+    )
+  endif()
+  string(COMPARE EQUAL "${dir}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("Empty 'dir' argument")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_URL empty")
+  endif()
+
+  set(done_location "${dir}/DONE")
+  set(sha1_location "${dir}/SHA1")
+
+  set(build_dir "${dir}/Build")
+  set(cmakelists "${dir}/CMakeLists.txt")
+
+  hunter_gate_lock("${dir}")
+  if(EXISTS "${done_location}")
+    # while waiting for lock other instance can do all the job
+    hunter_gate_status_debug("File '${done_location}' found, skip install")
+    return()
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
+
+  # Disabling languages speeds up a little bit, reduces noise in the output
+  # and avoids path too long windows error
+  file(
+      WRITE
+      "${cmakelists}"
+      "cmake_minimum_required(VERSION 3.0)\n"
+      "project(HunterDownload LANGUAGES NONE)\n"
+      "include(ExternalProject)\n"
+      "ExternalProject_Add(\n"
+      "    Hunter\n"
+      "    URL\n"
+      "    \"${HUNTER_GATE_URL}\"\n"
+      "    URL_HASH\n"
+      "    SHA1=${HUNTER_GATE_SHA1}\n"
+      "    DOWNLOAD_DIR\n"
+      "    \"${dir}\"\n"
+      "    SOURCE_DIR\n"
+      "    \"${dir}/Unpacked\"\n"
+      "    CONFIGURE_COMMAND\n"
+      "    \"\"\n"
+      "    BUILD_COMMAND\n"
+      "    \"\"\n"
+      "    INSTALL_COMMAND\n"
+      "    \"\"\n"
+      ")\n"
+  )
+
+  if(HUNTER_STATUS_DEBUG)
+    set(logging_params "")
+  else()
+    set(logging_params OUTPUT_QUIET)
+  endif()
+
+  hunter_gate_status_debug("Run generate")
+
+  # Need to add toolchain file too.
+  # Otherwise on Visual Studio + MDD this will fail with error:
+  # "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
+  if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")
+  else()
+    # 'toolchain_arg' can't be empty
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
+  endif()
+
+  execute_process(
+      COMMAND "${CMAKE_COMMAND}" "-H${dir}" "-B${build_dir}" "-G${CMAKE_GENERATOR}" "${toolchain_arg}"
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error("Configure project failed")
+  endif()
+
+  hunter_gate_status_print(
+      "Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
+      "  ${HUNTER_GATE_URL}"
+      "  -> ${dir}"
+  )
+  execute_process(
+      COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error("Build project failed")
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
+  file(WRITE "${done_location}" "DONE")
+
+  hunter_gate_status_debug("Finished")
+endfunction()
+
+# Must be a macro so master file 'cmake/Hunter' can
+# apply all variables easily just by 'include' command
+# (otherwise PARENT_SCOPE magic needed)
+macro(HunterGate)
+  if(HUNTER_GATE_DONE)
+    # variable HUNTER_GATE_DONE set explicitly for external project
+    # (see `hunter_download`)
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+
+  # First HunterGate command will init Hunter, others will be ignored
+  get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
+
+  if(NOT HUNTER_ENABLED)
+    # Empty function to avoid error "unknown function"
+    function(hunter_add_package)
+    endfunction()
+  elseif(_hunter_gate_done)
+    hunter_gate_status_debug("Secondary HunterGate (use old settings)")
+    hunter_gate_self(
+        "${HUNTER_CACHED_ROOT}"
+        "${HUNTER_VERSION}"
+        "${HUNTER_SHA1}"
+        _hunter_self
+    )
+    include("${_hunter_self}/cmake/Hunter")
+  else()
+    set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
+
+    string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
+    if(_have_project_name)
+      hunter_gate_fatal_error(
+          "Please set HunterGate *before* 'project' command. "
+          "Detected project: ${PROJECT_NAME}"
+          WIKI "error.huntergate.before.project"
+      )
+    endif()
+
+    cmake_parse_arguments(
+        HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
+    )
+
+    string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
+    string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
+    string(
+        COMPARE
+        NOTEQUAL
+        "${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+        ""
+        _have_unparsed
+    )
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
+
+    if(_have_unparsed)
+      hunter_gate_user_error(
+          "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+      )
+    endif()
+    if(_empty_sha1)
+      hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
+    endif()
+    if(_empty_url)
+      hunter_gate_user_error("URL suboption of HunterGate is mandatory")
+    endif()
+    if(_have_global)
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
+      endif()
+    endif()
+    if(HUNTER_GATE_LOCAL)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
+      endif()
+    endif()
+    if(_have_filepath)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
+      endif()
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
+      endif()
+    endif()
+
+    hunter_gate_detect_root() # set HUNTER_GATE_ROOT
+
+    # Beautify path, fix probable problems with windows path slashes
+    get_filename_component(
+        HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
+    )
+    hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
+    if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
+      string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
+      if(NOT _contain_spaces EQUAL -1)
+        hunter_gate_fatal_error(
+            "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
+            "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
+            "(Use at your own risk!)"
+            WIKI "error.spaces.in.hunter.root"
+        )
+      endif()
+    endif()
+
+    string(
+        REGEX
+        MATCH
+        "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
+        HUNTER_GATE_VERSION
+        "${HUNTER_GATE_URL}"
+    )
+    string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
+    if(_is_empty)
+      set(HUNTER_GATE_VERSION "unknown")
+    endif()
+
+    hunter_gate_self(
+        "${HUNTER_GATE_ROOT}"
+        "${HUNTER_GATE_VERSION}"
+        "${HUNTER_GATE_SHA1}"
+        _hunter_self
+    )
+
+    set(_master_location "${_hunter_self}/cmake/Hunter")
+    if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
+      # Hunter downloaded manually (e.g. by 'git clone')
+      set(_unused "xxxxxxxxxx")
+      set(HUNTER_GATE_SHA1 "${_unused}")
+      set(HUNTER_GATE_VERSION "${_unused}")
+    else()
+      get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
+      set(_done_location "${_archive_id_location}/DONE")
+      set(_sha1_location "${_archive_id_location}/SHA1")
+
+      # Check Hunter already downloaded by HunterGate
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_download("${_archive_id_location}")
+      endif()
+
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_internal_error("hunter_gate_download failed")
+      endif()
+
+      if(NOT EXISTS "${_sha1_location}")
+        hunter_gate_internal_error("${_sha1_location} not found")
+      endif()
+      file(READ "${_sha1_location}" _sha1_value)
+      string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
+      if(NOT _is_equal)
+        hunter_gate_internal_error(
+            "Short SHA1 collision:"
+            "  ${_sha1_value} (from ${_sha1_location})"
+            "  ${HUNTER_GATE_SHA1} (HunterGate)"
+        )
+      endif()
+      if(NOT EXISTS "${_master_location}")
+        hunter_gate_user_error(
+            "Master file not found:"
+            "  ${_master_location}"
+            "try to update Hunter/HunterGate"
+        )
+      endif()
+    endif()
+    include("${_master_location}")
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+endmacro()
\ No newline at end of file
diff --git a/cmake/sanitize-helpers.cmake b/cmake/sanitize-helpers.cmake
new file mode 100644
index 0000000..6f3decd
--- /dev/null
+++ b/cmake/sanitize-helpers.cmake
@@ -0,0 +1,170 @@
+# The MIT License (MIT)
+#
+# Copyright (c)
+#   2013 Matthew Arsenault
+#   2015-2016 RWTH Aachen University, Federal Republic of Germany
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# Helper function to get the language of a source file.
+function (sanitizer_lang_of_source FILE RETURN_VAR)
+    get_filename_component(FILE_EXT "${FILE}" EXT)
+    string(TOLOWER "${FILE_EXT}" FILE_EXT)
+    string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT)
+
+    get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
+    foreach (LANG ${ENABLED_LANGUAGES})
+        list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP)
+        if (NOT ${TEMP} EQUAL -1)
+            set(${RETURN_VAR} "${LANG}" PARENT_SCOPE)
+            return()
+        endif ()
+    endforeach()
+
+    set(${RETURN_VAR} "" PARENT_SCOPE)
+endfunction ()
+
+
+# Helper function to get compilers used by a target.
+function (sanitizer_target_compilers TARGET RETURN_VAR)
+    # Check if all sources for target use the same compiler. If a target uses
+    # e.g. C and Fortran mixed and uses different compilers (e.g. clang and
+    # gfortran) this can trigger huge problems, because different compilers may
+    # use different implementations for sanitizers.
+    set(BUFFER "")
+    get_target_property(TSOURCES ${TARGET} SOURCES)
+    foreach (FILE ${TSOURCES})
+        # If expression was found, FILE is a generator-expression for an object
+        # library. Object libraries will be ignored.
+        string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE})
+        if ("${_file}" STREQUAL "")
+            sanitizer_lang_of_source(${FILE} LANG)
+            if (LANG)
+                list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID})
+            endif ()
+        endif ()
+    endforeach ()
+
+    list(REMOVE_DUPLICATES BUFFER)
+    set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE)
+endfunction ()
+
+
+# Helper function to check compiler flags for language compiler.
+function (sanitizer_check_compiler_flag FLAG LANG VARIABLE)
+    if (${LANG} STREQUAL "C")
+        include(CheckCCompilerFlag)
+        check_c_compiler_flag("${FLAG}" ${VARIABLE})
+
+    elseif (${LANG} STREQUAL "CXX")
+        include(CheckCXXCompilerFlag)
+        check_cxx_compiler_flag("${FLAG}" ${VARIABLE})
+
+    elseif (${LANG} STREQUAL "Fortran")
+        # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible
+        # with older Cmake versions, we will check if this module is present
+        # before we use it. Otherwise we will define Fortran coverage support as
+        # not available.
+        include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED)
+        if (INCLUDED)
+            check_fortran_compiler_flag("${FLAG}" ${VARIABLE})
+        elseif (NOT CMAKE_REQUIRED_QUIET)
+            message(STATUS "Performing Test ${VARIABLE}")
+            message(STATUS "Performing Test ${VARIABLE}"
+                " - Failed (Check not supported)")
+        endif ()
+    endif()
+endfunction ()
+
+
+# Helper function to test compiler flags.
+function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX)
+    set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY})
+
+    get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
+    foreach (LANG ${ENABLED_LANGUAGES})
+        # Sanitizer flags are not dependend on language, but the used compiler.
+        # So instead of searching flags foreach language, search flags foreach
+        # compiler used.
+        set(COMPILER ${CMAKE_${LANG}_COMPILER_ID})
+        if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS)
+            foreach (FLAG ${FLAG_CANDIDATES})
+                if(NOT CMAKE_REQUIRED_QUIET)
+                    message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]")
+                endif()
+
+                set(CMAKE_REQUIRED_FLAGS "${FLAG}")
+                unset(${PREFIX}_FLAG_DETECTED CACHE)
+                sanitizer_check_compiler_flag("${FLAG}" ${LANG}
+                    ${PREFIX}_FLAG_DETECTED)
+
+                if (${PREFIX}_FLAG_DETECTED)
+                    # If compiler is a GNU compiler, search for static flag, if
+                    # SANITIZE_LINK_STATIC is enabled.
+                    if (SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU"))
+                        string(TOLOWER ${PREFIX} PREFIX_lower)
+                        sanitizer_check_compiler_flag(
+                            "-static-lib${PREFIX_lower}" ${LANG}
+                            ${PREFIX}_STATIC_FLAG_DETECTED)
+
+                        if (${PREFIX}_STATIC_FLAG_DETECTED)
+                            set(FLAG "-static-lib${PREFIX_lower} ${FLAG}")
+                        endif ()
+                    endif ()
+
+                    set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING
+                        "${NAME} flags for ${COMPILER} compiler.")
+                    mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS)
+                    break()
+                endif ()
+            endforeach ()
+
+            if (NOT ${PREFIX}_FLAG_DETECTED)
+                set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING
+                    "${NAME} flags for ${COMPILER} compiler.")
+                mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS)
+
+                message(WARNING "${NAME} is not available for ${COMPILER} "
+                        "compiler. Targets using this compiler will be "
+                        "compiled without ${NAME}.")
+            endif ()
+        endif ()
+    endforeach ()
+endfunction ()
+
+
+# Helper to assign sanitizer flags for TARGET.
+function (saitizer_add_flags TARGET NAME PREFIX)
+    # Get list of compilers used by target and check, if sanitizer is available
+    # for this target. Other compiler checks like check for conflicting
+    # compilers will be done in add_sanitizers function.
+    sanitizer_target_compilers(${TARGET} TARGET_COMPILER)
+    list(LENGTH TARGET_COMPILER NUM_COMPILERS)
+    if ("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "")
+        return()
+    endif()
+
+    # Set compile- and link-flags for target.
+    set_property(TARGET ${TARGET} APPEND_STRING
+        PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}")
+    set_property(TARGET ${TARGET} APPEND_STRING
+        PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}")
+    set_property(TARGET ${TARGET} APPEND_STRING
+        PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}")
+endfunction ()
diff --git a/crow b/crow
new file mode 160000
index 0000000..4e39b23
--- /dev/null
+++ b/crow
@@ -0,0 +1 @@
+Subproject commit 4e39b23e455e455f1878b3e68d729a1737f3e431
diff --git a/g3log b/g3log
new file mode 160000
index 0000000..a48a486
--- /dev/null
+++ b/g3log
@@ -0,0 +1 @@
+Subproject commit a48a4860fd6acd94ef1bf66f398b7a8c6e096290
diff --git a/src/ColorCoutG3Sink.hpp b/src/ColorCoutG3Sink.hpp
new file mode 100644
index 0000000..cd98fac
--- /dev/null
+++ b/src/ColorCoutG3Sink.hpp
@@ -0,0 +1,26 @@
+#pragma once
+namespace crow
+{
+  struct ColorCoutSink {
+
+  // Linux xterm color
+  // http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
+    enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};
+
+    FG_Color GetColor(const LEVELS level) const {
+      if (level.value == WARNING.value) { return YELLOW; }
+      if (level.value == DEBUG.value) { return GREEN; }
+      if (g3::internal::wasFatal(level)) { return RED; }
+
+      return WHITE;
+    }
+    
+    void ReceiveLogMessage(g3::LogMessageMover logEntry) {
+      auto level = logEntry.get()._level;
+      auto color = GetColor(level);
+
+      std::cout << "\033[" << color << "m" 
+        << logEntry.get().toString() << "\033[m";
+    }
+  };
+}
\ No newline at end of file
diff --git a/src/example.cpp b/src/example.cpp
new file mode 100644
index 0000000..ed893e6
--- /dev/null
+++ b/src/example.cpp
@@ -0,0 +1,199 @@
+#include "crow/query_string.h"
+#include "crow/http_parser_merged.h"
+#include "crow/ci_map.h"
+//#include "crow/TinySHA1.hpp"
+#include "crow/settings.h"
+#include "crow/socket_adaptors.h"
+#include "crow/json.h"
+#include "crow/mustache.h"
+#include "crow/logging.h"
+#include "crow/dumb_timer_queue.h"
+#include "crow/utility.h"
+#include "crow/common.h"
+#include "crow/http_request.h"
+#include "crow/websocket.h"
+#include "crow/parser.h"
+#include "crow/http_response.h"
+#include "crow/middleware.h"
+#include "crow/routing.h"
+#include "crow/middleware_context.h"
+#include "crow/http_connection.h"
+#include "crow/http_server.h"
+#include "crow/app.h"
+
+#include "ColorCoutG3Sink.hpp"
+
+#include "ssl_key_handler.hpp"
+#include <iostream>
+#include <string>
+
+
+
+struct ExampleMiddleware 
+{
+    std::string message;
+
+    ExampleMiddleware() 
+    {
+        message = "foo";
+    }
+
+    void setMessage(std::string newMsg)
+    {
+        message = newMsg;
+    }
+
+    struct context
+    {
+    };
+
+    void before_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
+    {
+        CROW_LOG_DEBUG << " - MESSAGE: " << message;
+    }
+
+    void after_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
+    {
+        // no-op
+    }
+};
+
+
+
+int main(int argc, char** argv)
+{
+   auto worker = g3::LogWorker::createLogWorker();
+   auto handle= worker->addDefaultLogger(argv[0], "/tmp/");
+   g3::initializeLogging(worker.get());
+   auto log_file_name = handle->call(&g3::FileSink::fileName);
+   auto stdout_handler = std::make_unique<crow::ColorCoutSink>();
+   auto sink_handle = worker->addSink(stdout_handler,
+                                     &crow::ColorCoutSink::ReceiveLogMessage);
+
+   LOG(DEBUG) << "Logging to " << log_file_name.get() << "\n";
+
+    std::string ssl_pem_file("server.pem");
+    ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
+    //auto handler2 = std::make_shared<ExampleLogHandler>();
+    //crow::logger::setHandler(handler2.get());
+    crow::App<ExampleMiddleware> app;
+
+    app.get_middleware<ExampleMiddleware>().setMessage("hello");
+
+    CROW_ROUTE(app, "/")
+        .name("hello")
+    ([]{
+        return "Hello World!";
+    });
+
+    CROW_ROUTE(app, "/about")
+    ([](){
+        return "About Crow example.";
+    });
+
+    // a request to /path should be forwarded to /path/
+    CROW_ROUTE(app, "/path/")
+    ([](){
+        return "Trailing slash test case..";
+    });
+
+
+    // simple json response
+    // To see it in action enter {ip}:18080/json
+    CROW_ROUTE(app, "/json")
+    ([]{
+        crow::json::wvalue x;
+        x["message"] = "Hello, World!";
+        return x;
+    });
+
+    // To see it in action enter {ip}:18080/hello/{integer_between -2^32 and 100} and you should receive
+    // {integer_between -2^31 and 100} bottles of beer!
+    CROW_ROUTE(app,"/hello/<int>")
+    ([](int count){
+        if (count > 100)
+            return crow::response(400);
+        std::ostringstream os;
+        os << count << " bottles of beer!";
+        return crow::response(os.str());
+    });
+
+    // To see it in action submit {ip}:18080/add/1/2 and you should receive 3 (exciting, isn't it)
+    CROW_ROUTE(app,"/add/<int>/<int>")
+    ([](const crow::request& /*req*/, crow::response& res, int a, int b){
+        std::ostringstream os;
+        os << a+b;
+        res.write(os.str());
+        res.end();
+    });
+
+    // Compile error with message "Handler type is mismatched with URL paramters"
+    //CROW_ROUTE(app,"/another/<int>")
+    //([](int a, int b){
+        //return crow::response(500);
+    //});
+
+    // more json example
+
+    // To see it in action, I recommend to use the Postman Chrome extension:
+    //      * Set the address to {ip}:18080/add_json
+    //      * Set the method to post
+    //      * Select 'raw' and then JSON
+    //      * Add {"a": 1, "b": 1}
+    //      * Send and you should receive 2
+
+    // A simpler way for json example:
+    //      * curl -d '{"a":1,"b":2}' {ip}:18080/add_json
+    CROW_ROUTE(app, "/add_json")
+        .methods("POST"_method)
+    ([](const crow::request& req){
+        auto x = crow::json::load(req.body);
+        if (!x)
+            return crow::response(400);
+        int sum = x["a"].i()+x["b"].i();
+        std::ostringstream os;
+        os << sum;
+        return crow::response{os.str()};
+    });
+
+    // Example of a request taking URL parameters
+    // If you want to activate all the functions just query
+    // {ip}:18080/params?foo='blabla'&pew=32&count[]=a&count[]=b
+    CROW_ROUTE(app, "/params")
+    ([](const crow::request& req){
+        std::ostringstream os;
+
+        // To get a simple string from the url params
+        // To see it in action /params?foo='blabla'
+        os << "Params: " << req.url_params << "\n\n"; 
+        os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n";
+
+        // To get a double from the request
+        // To see in action submit something like '/params?pew=42'
+        if(req.url_params.get("pew") != nullptr) {
+            double countD = boost::lexical_cast<double>(req.url_params.get("pew"));
+            os << "The value of 'pew' is " <<  countD << '\n';
+        }
+
+        // To get a list from the request
+        // You have to submit something like '/params?count[]=a&count[]=b' to have a list with two values (a and b)
+        auto count = req.url_params.get_list("count");
+        os << "The key 'count' contains " << count.size() << " value(s).\n";
+        for(const auto& countVal : count) {
+            os << " - " << countVal << '\n';
+        }
+        return crow::response{os.str()};
+    });    
+
+    CROW_ROUTE(app, "/large")
+    ([]{
+        return std::string(512*1024, ' ');
+    });
+
+    // ignore all log
+    crow::logger::setLogLevel(crow::LogLevel::DEBUG);
+
+    app.port(18080)
+        .multithreaded()
+        .run();
+}
diff --git a/src/ssl_key_handler.hpp b/src/ssl_key_handler.hpp
new file mode 100644
index 0000000..a658d9c
--- /dev/null
+++ b/src/ssl_key_handler.hpp
@@ -0,0 +1,182 @@
+#pragma once
+
+#include <openssl/bio.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+
+namespace ensuressl
+{
+static void init_openssl(void);
+static void cleanup_openssl(void);
+static EVP_PKEY *create_rsa_key(void);
+static void handle_openssl_error(void);
+
+inline bool verify_openssl_key_cert(const std::string &filepath)
+{
+    bool private_key_valid = false;
+    bool cert_valid = false;
+    FILE *file = fopen(filepath.c_str(), "r");
+    if (file != NULL){   
+        EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
+        int rc;
+        if (pkey) {
+            int type = EVP_PKEY_type(pkey->type);
+            switch (type) {
+                case EVP_PKEY_RSA:
+                case EVP_PKEY_RSA2: {
+                    RSA *rsa = EVP_PKEY_get1_RSA(pkey);
+                    rc = RSA_check_key(rsa);
+                    if (rc == 1) {
+                        private_key_valid = true;
+                    }
+
+                    //RSA_free(rsa);
+
+                    break;
+                }
+                default:
+                    break;
+            }
+
+            if (private_key_valid) {
+                X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
+                unsigned long err = ERR_get_error();
+
+                rc = X509_verify(x509, pkey);
+                err = ERR_get_error();
+                if (err == 0 && rc == 1) {
+                    cert_valid = true;
+                }
+            }
+
+            EVP_PKEY_free(pkey);
+        }
+        fclose(file);
+    }
+    return cert_valid;
+}
+
+inline void generate_ssl_certificate(const std::string &filepath)
+{
+    EVP_PKEY *pPrivKey = NULL;
+    FILE *pFile = NULL;
+    init_openssl();
+
+    pPrivKey = create_rsa_key();
+
+    // Use this code to directly generate a certificate
+    X509 *x509;
+    x509 = X509_new();
+    if (x509) {
+        // TODO get actually random int
+        ASN1_INTEGER_set(X509_get_serialNumber(x509), 1584);
+
+        // not before this moment
+        X509_gmtime_adj(X509_get_notBefore(x509), 0);
+        // Cert is valid for 10 years
+        X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * 365L * 10L);
+
+        // set the public key to the key we just generated
+        X509_set_pubkey(x509, pPrivKey);
+
+        // Get the subject name
+        X509_NAME *name;
+        name = X509_get_subject_name(x509);
+
+        X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1,
+                                   -1, 0);
+        X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
+                                   (unsigned char *)"Intel BMC", -1, -1, 0);
+        X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+                                   (unsigned char *)"testhost", -1, -1, 0);
+        // set the CSR options
+        X509_set_issuer_name(x509, name);
+
+        // Sign the certificate with our private key
+        X509_sign(x509, pPrivKey, EVP_sha256());
+
+        pFile = fopen(filepath.c_str(), "wt");
+
+        if (pFile) {
+            PEM_write_PrivateKey(pFile, pPrivKey, NULL, NULL, 0, 0, NULL);
+            PEM_write_X509(pFile, x509);
+            fclose(pFile);
+            pFile = NULL;
+        }
+
+        X509_free(x509);
+    }
+
+    if (pPrivKey) {
+        EVP_PKEY_free(pPrivKey);
+        pPrivKey = NULL;
+    }
+
+    //cleanup_openssl();
+}
+
+EVP_PKEY *create_rsa_key(void)
+{
+    RSA *pRSA = NULL;
+    EVP_PKEY *pKey = NULL;
+    pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
+    pKey = EVP_PKEY_new();
+    if (pRSA && pKey && EVP_PKEY_assign_RSA(pKey, pRSA)) {
+        /* pKey owns pRSA from now */
+        if (RSA_check_key(pRSA) <= 0) {
+            fprintf(stderr, "RSA_check_key failed.\n");
+            handle_openssl_error();
+            EVP_PKEY_free(pKey);
+            pKey = NULL;
+        }
+    } else {
+        handle_openssl_error();
+        if (pRSA) {
+            RSA_free(pRSA);
+            pRSA = NULL;
+        }
+        if (pKey) {
+            EVP_PKEY_free(pKey);
+            pKey = NULL;
+        }
+    }
+    return pKey;
+}
+
+void init_openssl(void)
+{
+    if (SSL_library_init()) {
+        SSL_load_error_strings();
+        OpenSSL_add_all_algorithms();
+        RAND_load_file("/dev/urandom", 1024);
+    } else
+        exit(EXIT_FAILURE);
+}
+
+void cleanup_openssl(void)
+{
+    CRYPTO_cleanup_all_ex_data();
+    ERR_free_strings();
+    ERR_remove_thread_state(0);
+    EVP_cleanup();
+}
+
+void handle_openssl_error(void) { ERR_print_errors_fp(stderr); }
+inline void ensure_openssl_key_present_and_valid(const std::string &filepath)
+{
+    bool pem_file_valid = false;
+
+    pem_file_valid = verify_openssl_key_cert(filepath);
+
+    if (!pem_file_valid) {
+        generate_ssl_certificate(filepath);
+    }
+}
+}
\ No newline at end of file