diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e0a3916c0237c639a05f3aa17fba70dd6fd6e491
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.rest_build
+binaries
+
diff --git a/API/.build/CMakeCache.txt b/API/.build/CMakeCache.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c9209e078c58f3c4a7407258da080a1f8bf684ca
--- /dev/null
+++ b/API/.build/CMakeCache.txt
@@ -0,0 +1,381 @@
+# This is the CMakeCache file.
+# For build in directory: /home/tingjie/src/operating-system/API/.build
+# It was generated by CMake: /usr/bin/cmake
+# You can edit this file to change values found and used by cmake.
+# If you do not want to change any of the values, simply exit the editor.
+# If you do want to change a value, simply edit, save, and exit the editor.
+# The syntax for the file is as follows:
+# KEY:TYPE=VALUE
+# KEY is the name of a variable in the cache.
+# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
+# VALUE is the current value for the KEY.
+
+########################
+# EXTERNAL cache entries
+########################
+
+//Path to a program.
+CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line
+
+//Path to a program.
+CMAKE_AR:FILEPATH=/usr/bin/ar
+
+//Choose the type of build, options are: None Debug Release RelWithDebInfo
+// MinSizeRel ...
+CMAKE_BUILD_TYPE:STRING=
+
+//Enable/Disable color output during build.
+CMAKE_COLOR_MAKEFILE:BOOL=ON
+
+//CXX compiler
+CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++
+
+//A wrapper around 'ar' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-9
+
+//A wrapper around 'ranlib' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-9
+
+//Flags used by the CXX compiler during all build types.
+CMAKE_CXX_FLAGS:STRING=
+
+//Flags used by the CXX compiler during DEBUG builds.
+CMAKE_CXX_FLAGS_DEBUG:STRING=-g
+
+//Flags used by the CXX compiler during MINSIZEREL builds.
+CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
+
+//Flags used by the CXX compiler during RELEASE builds.
+CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
+
+//Flags used by the CXX compiler during RELWITHDEBINFO builds.
+CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
+
+//C compiler
+CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc
+
+//A wrapper around 'ar' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-9
+
+//A wrapper around 'ranlib' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-9
+
+//Flags used by the C compiler during all build types.
+CMAKE_C_FLAGS:STRING=
+
+//Flags used by the C compiler during DEBUG builds.
+CMAKE_C_FLAGS_DEBUG:STRING=-g
+
+//Flags used by the C compiler during MINSIZEREL builds.
+CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
+
+//Flags used by the C compiler during RELEASE builds.
+CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
+
+//Flags used by the C compiler during RELWITHDEBINFO builds.
+CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
+
+//Path to a program.
+CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND
+
+//Flags used by the linker during all build types.
+CMAKE_EXE_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during DEBUG builds.
+CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during MINSIZEREL builds.
+CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during RELEASE builds.
+CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during RELWITHDEBINFO builds.
+CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//Enable/Disable output of compile commands during generation.
+CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF
+
+//Install path prefix, prepended onto install directories.
+CMAKE_INSTALL_PREFIX:PATH=/usr/local
+
+//Path to a program.
+CMAKE_LINKER:FILEPATH=/usr/bin/ld
+
+//Path to a program.
+CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make
+
+//Flags used by the linker during the creation of modules during
+// all build types.
+CMAKE_MODULE_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during the creation of modules during
+// DEBUG builds.
+CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during the creation of modules during
+// MINSIZEREL builds.
+CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during the creation of modules during
+// RELEASE builds.
+CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during the creation of modules during
+// RELWITHDEBINFO builds.
+CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//Path to a program.
+CMAKE_NM:FILEPATH=/usr/bin/nm
+
+//Path to a program.
+CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy
+
+//Path to a program.
+CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump
+
+//Value Computed by CMake
+CMAKE_PROJECT_DESCRIPTION:STATIC=
+
+//Value Computed by CMake
+CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
+
+//Value Computed by CMake
+CMAKE_PROJECT_NAME:STATIC=snakeoil_api
+
+//Value Computed by CMake
+CMAKE_PROJECT_VERSION:STATIC=1.2.4
+
+//Value Computed by CMake
+CMAKE_PROJECT_VERSION_MAJOR:STATIC=1
+
+//Value Computed by CMake
+CMAKE_PROJECT_VERSION_MINOR:STATIC=2
+
+//Value Computed by CMake
+CMAKE_PROJECT_VERSION_PATCH:STATIC=4
+
+//Value Computed by CMake
+CMAKE_PROJECT_VERSION_TWEAK:STATIC=
+
+//Path to a program.
+CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib
+
+//Path to a program.
+CMAKE_READELF:FILEPATH=/usr/bin/readelf
+
+//Flags used by the linker during the creation of shared libraries
+// during all build types.
+CMAKE_SHARED_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during DEBUG builds.
+CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during MINSIZEREL builds.
+CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during RELEASE builds.
+CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during RELWITHDEBINFO builds.
+CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//If set, runtime paths are not added when installing shared libraries,
+// but are added when building.
+CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
+
+//If set, runtime paths are not added when using shared libraries.
+CMAKE_SKIP_RPATH:BOOL=NO
+
+//Flags used by the linker during the creation of static libraries
+// during all build types.
+CMAKE_STATIC_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during DEBUG builds.
+CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during MINSIZEREL builds.
+CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during RELEASE builds.
+CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during RELWITHDEBINFO builds.
+CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//Path to a program.
+CMAKE_STRIP:FILEPATH=/usr/bin/strip
+
+//If this value is on, makefiles will be generated without the
+// .SILENT directive, and all commands will be echoed to the console
+// during the make.  This is useful for debugging only. With Visual
+// Studio IDE projects all commands are done without /nologo.
+CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
+
+//Value Computed by CMake
+snakeoil_api_BINARY_DIR:STATIC=/home/tingjie/src/operating-system/API/.build
+
+//Value Computed by CMake
+snakeoil_api_SOURCE_DIR:STATIC=/home/tingjie/src/operating-system/API
+
+
+########################
+# INTERNAL cache entries
+########################
+
+//ADVANCED property for variable: CMAKE_ADDR2LINE
+CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_AR
+CMAKE_AR-ADVANCED:INTERNAL=1
+//This is the directory where this CMakeCache.txt was created
+CMAKE_CACHEFILE_DIR:INTERNAL=/home/tingjie/src/operating-system/API/.build
+//Major version of cmake used to create the current loaded cache
+CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
+//Minor version of cmake used to create the current loaded cache
+CMAKE_CACHE_MINOR_VERSION:INTERNAL=16
+//Patch version of cmake used to create the current loaded cache
+CMAKE_CACHE_PATCH_VERSION:INTERNAL=3
+//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE
+CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1
+//Path to CMake executable.
+CMAKE_COMMAND:INTERNAL=/usr/bin/cmake
+//Path to cpack program executable.
+CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack
+//Path to ctest program executable.
+CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest
+//ADVANCED property for variable: CMAKE_CXX_COMPILER
+CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR
+CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB
+CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS
+CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
+CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
+CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
+CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
+CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_COMPILER
+CMAKE_C_COMPILER-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_COMPILER_AR
+CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB
+CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS
+CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
+CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
+CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
+CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
+CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_DLLTOOL
+CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
+//Executable file format
+CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
+CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
+CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
+CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
+CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
+CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
+//Name of external makefile project generator.
+CMAKE_EXTRA_GENERATOR:INTERNAL=
+//Name of generator.
+CMAKE_GENERATOR:INTERNAL=Unix Makefiles
+//Generator instance identifier.
+CMAKE_GENERATOR_INSTANCE:INTERNAL=
+//Name of generator platform.
+CMAKE_GENERATOR_PLATFORM:INTERNAL=
+//Name of generator toolset.
+CMAKE_GENERATOR_TOOLSET:INTERNAL=
+//Source directory with the top level CMakeLists.txt file for this
+// project
+CMAKE_HOME_DIRECTORY:INTERNAL=/home/tingjie/src/operating-system/API
+//Install .so files without execute permission.
+CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1
+//ADVANCED property for variable: CMAKE_LINKER
+CMAKE_LINKER-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MAKE_PROGRAM
+CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
+CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
+CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
+CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
+CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_NM
+CMAKE_NM-ADVANCED:INTERNAL=1
+//number of local generators
+CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
+//ADVANCED property for variable: CMAKE_OBJCOPY
+CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_OBJDUMP
+CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
+//Platform information initialized
+CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_RANLIB
+CMAKE_RANLIB-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_READELF
+CMAKE_READELF-ADVANCED:INTERNAL=1
+//Path to CMake installation.
+CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.16
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
+CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
+CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
+CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
+CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
+CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SKIP_RPATH
+CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
+CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
+CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
+CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
+CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STRIP
+CMAKE_STRIP-ADVANCED:INTERNAL=1
+//uname command
+CMAKE_UNAME:INTERNAL=/bin/uname
+//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
+CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
+
diff --git a/API/.build/CMakeFiles/3.16.3/CMakeCCompiler.cmake b/API/.build/CMakeFiles/3.16.3/CMakeCCompiler.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..b9e0657dda4f5601ffbffc1b5dbab427c50aa126
--- /dev/null
+++ b/API/.build/CMakeFiles/3.16.3/CMakeCCompiler.cmake
@@ -0,0 +1,76 @@
+set(CMAKE_C_COMPILER "/usr/bin/cc")
+set(CMAKE_C_COMPILER_ARG1 "")
+set(CMAKE_C_COMPILER_ID "GNU")
+set(CMAKE_C_COMPILER_VERSION "9.3.0")
+set(CMAKE_C_COMPILER_VERSION_INTERNAL "")
+set(CMAKE_C_COMPILER_WRAPPER "")
+set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "11")
+set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert")
+set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes")
+set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros")
+set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert")
+
+set(CMAKE_C_PLATFORM_ID "Linux")
+set(CMAKE_C_SIMULATE_ID "")
+set(CMAKE_C_COMPILER_FRONTEND_VARIANT "")
+set(CMAKE_C_SIMULATE_VERSION "")
+
+
+
+set(CMAKE_AR "/usr/bin/ar")
+set(CMAKE_C_COMPILER_AR "/usr/bin/gcc-ar-9")
+set(CMAKE_RANLIB "/usr/bin/ranlib")
+set(CMAKE_C_COMPILER_RANLIB "/usr/bin/gcc-ranlib-9")
+set(CMAKE_LINKER "/usr/bin/ld")
+set(CMAKE_MT "")
+set(CMAKE_COMPILER_IS_GNUCC 1)
+set(CMAKE_C_COMPILER_LOADED 1)
+set(CMAKE_C_COMPILER_WORKS TRUE)
+set(CMAKE_C_ABI_COMPILED TRUE)
+set(CMAKE_COMPILER_IS_MINGW )
+set(CMAKE_COMPILER_IS_CYGWIN )
+if(CMAKE_COMPILER_IS_CYGWIN)
+  set(CYGWIN 1)
+  set(UNIX 1)
+endif()
+
+set(CMAKE_C_COMPILER_ENV_VAR "CC")
+
+if(CMAKE_COMPILER_IS_MINGW)
+  set(MINGW 1)
+endif()
+set(CMAKE_C_COMPILER_ID_RUN 1)
+set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
+set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
+set(CMAKE_C_LINKER_PREFERENCE 10)
+
+# Save compiler ABI information.
+set(CMAKE_C_SIZEOF_DATA_PTR "8")
+set(CMAKE_C_COMPILER_ABI "ELF")
+set(CMAKE_C_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")
+
+if(CMAKE_C_SIZEOF_DATA_PTR)
+  set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_C_COMPILER_ABI)
+  set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}")
+endif()
+
+if(CMAKE_C_LIBRARY_ARCHITECTURE)
+  set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")
+endif()
+
+set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "")
+if(CMAKE_C_CL_SHOWINCLUDES_PREFIX)
+  set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}")
+endif()
+
+
+
+
+
+set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/9/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include")
+set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;c")
+set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/9;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib")
+set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
diff --git a/API/.build/CMakeFiles/3.16.3/CMakeCXXCompiler.cmake b/API/.build/CMakeFiles/3.16.3/CMakeCXXCompiler.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..d9b994ef4ef51869eefa4c364fca17e727a6c64b
--- /dev/null
+++ b/API/.build/CMakeFiles/3.16.3/CMakeCXXCompiler.cmake
@@ -0,0 +1,88 @@
+set(CMAKE_CXX_COMPILER "/usr/bin/c++")
+set(CMAKE_CXX_COMPILER_ARG1 "")
+set(CMAKE_CXX_COMPILER_ID "GNU")
+set(CMAKE_CXX_COMPILER_VERSION "9.3.0")
+set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "")
+set(CMAKE_CXX_COMPILER_WRAPPER "")
+set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "14")
+set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20")
+set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters")
+set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
+set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
+set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17")
+set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20")
+
+set(CMAKE_CXX_PLATFORM_ID "Linux")
+set(CMAKE_CXX_SIMULATE_ID "")
+set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "")
+set(CMAKE_CXX_SIMULATE_VERSION "")
+
+
+
+set(CMAKE_AR "/usr/bin/ar")
+set(CMAKE_CXX_COMPILER_AR "/usr/bin/gcc-ar-9")
+set(CMAKE_RANLIB "/usr/bin/ranlib")
+set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/gcc-ranlib-9")
+set(CMAKE_LINKER "/usr/bin/ld")
+set(CMAKE_MT "")
+set(CMAKE_COMPILER_IS_GNUCXX 1)
+set(CMAKE_CXX_COMPILER_LOADED 1)
+set(CMAKE_CXX_COMPILER_WORKS TRUE)
+set(CMAKE_CXX_ABI_COMPILED TRUE)
+set(CMAKE_COMPILER_IS_MINGW )
+set(CMAKE_COMPILER_IS_CYGWIN )
+if(CMAKE_COMPILER_IS_CYGWIN)
+  set(CYGWIN 1)
+  set(UNIX 1)
+endif()
+
+set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
+
+if(CMAKE_COMPILER_IS_MINGW)
+  set(MINGW 1)
+endif()
+set(CMAKE_CXX_COMPILER_ID_RUN 1)
+set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;CPP)
+set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
+
+foreach (lang C OBJC OBJCXX)
+  if (CMAKE_${lang}_COMPILER_ID_RUN)
+    foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS)
+      list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension})
+    endforeach()
+  endif()
+endforeach()
+
+set(CMAKE_CXX_LINKER_PREFERENCE 30)
+set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
+
+# Save compiler ABI information.
+set(CMAKE_CXX_SIZEOF_DATA_PTR "8")
+set(CMAKE_CXX_COMPILER_ABI "ELF")
+set(CMAKE_CXX_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")
+
+if(CMAKE_CXX_SIZEOF_DATA_PTR)
+  set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_CXX_COMPILER_ABI)
+  set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}")
+endif()
+
+if(CMAKE_CXX_LIBRARY_ARCHITECTURE)
+  set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")
+endif()
+
+set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "")
+if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX)
+  set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}")
+endif()
+
+
+
+
+
+set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/usr/include/c++/9;/usr/include/x86_64-linux-gnu/c++/9;/usr/include/c++/9/backward;/usr/lib/gcc/x86_64-linux-gnu/9/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include")
+set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;m;gcc;c")
+set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/9;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib")
+set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
diff --git a/API/.build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin b/API/.build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin
new file mode 100755
index 0000000000000000000000000000000000000000..96ce5c30ead653506cb9786a43024718bc6a20d8
Binary files /dev/null and b/API/.build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin differ
diff --git a/API/.build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin b/API/.build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin
new file mode 100755
index 0000000000000000000000000000000000000000..1fc6d8f5dbbb6652ca5406080e2e4cc7c8e7b70f
Binary files /dev/null and b/API/.build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin differ
diff --git a/API/.build/CMakeFiles/3.16.3/CMakeSystem.cmake b/API/.build/CMakeFiles/3.16.3/CMakeSystem.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..b17f414ee417c947193d3192bedc77ee7610c118
--- /dev/null
+++ b/API/.build/CMakeFiles/3.16.3/CMakeSystem.cmake
@@ -0,0 +1,15 @@
+set(CMAKE_HOST_SYSTEM "Linux-5.4.0-86-generic")
+set(CMAKE_HOST_SYSTEM_NAME "Linux")
+set(CMAKE_HOST_SYSTEM_VERSION "5.4.0-86-generic")
+set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")
+
+
+
+set(CMAKE_SYSTEM "Linux-5.4.0-86-generic")
+set(CMAKE_SYSTEM_NAME "Linux")
+set(CMAKE_SYSTEM_VERSION "5.4.0-86-generic")
+set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+
+set(CMAKE_CROSSCOMPILING "FALSE")
+
+set(CMAKE_SYSTEM_LOADED 1)
diff --git a/API/.build/CMakeFiles/3.16.3/CompilerIdC/CMakeCCompilerId.c b/API/.build/CMakeFiles/3.16.3/CompilerIdC/CMakeCCompilerId.c
new file mode 100644
index 0000000000000000000000000000000000000000..d884b50908c9852aad6d3b60781f4e529edc4d50
--- /dev/null
+++ b/API/.build/CMakeFiles/3.16.3/CompilerIdC/CMakeCCompilerId.c
@@ -0,0 +1,671 @@
+#ifdef __cplusplus
+# error "A C++ compiler has been selected for C."
+#endif
+
+#if defined(__18CXX)
+# define ID_VOID_MAIN
+#endif
+#if defined(__CLASSIC_C__)
+/* cv-qualifiers did not exist in K&R C */
+# define const
+# define volatile
+#endif
+
+
+/* Version number components: V=Version, R=Revision, P=Patch
+   Version date components:   YYYY=Year, MM=Month,   DD=Day  */
+
+#if defined(__INTEL_COMPILER) || defined(__ICC)
+# define COMPILER_ID "Intel"
+# if defined(_MSC_VER)
+#  define SIMULATE_ID "MSVC"
+# endif
+# if defined(__GNUC__)
+#  define SIMULATE_ID "GNU"
+# endif
+  /* __INTEL_COMPILER = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
+# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
+# if defined(__INTEL_COMPILER_UPDATE)
+#  define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
+# else
+#  define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER   % 10)
+# endif
+# if defined(__INTEL_COMPILER_BUILD_DATE)
+  /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
+#  define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
+# endif
+# if defined(_MSC_VER)
+   /* _MSC_VER = VVRR */
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
+# endif
+# if defined(__GNUC__)
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
+# elif defined(__GNUG__)
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
+# endif
+# if defined(__GNUC_MINOR__)
+#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+#  define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
+# endif
+
+#elif defined(__PATHCC__)
+# define COMPILER_ID "PathScale"
+# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
+# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
+# if defined(__PATHCC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
+# endif
+
+#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
+# define COMPILER_ID "Embarcadero"
+# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
+# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
+# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__     & 0xFFFF)
+
+#elif defined(__BORLANDC__)
+# define COMPILER_ID "Borland"
+  /* __BORLANDC__ = 0xVRR */
+# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
+# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
+
+#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
+# define COMPILER_ID "Watcom"
+   /* __WATCOMC__ = VVRR */
+# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
+# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
+# if (__WATCOMC__ % 10) > 0
+#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
+# endif
+
+#elif defined(__WATCOMC__)
+# define COMPILER_ID "OpenWatcom"
+   /* __WATCOMC__ = VVRP + 1100 */
+# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
+# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
+# if (__WATCOMC__ % 10) > 0
+#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
+# endif
+
+#elif defined(__SUNPRO_C)
+# define COMPILER_ID "SunPro"
+# if __SUNPRO_C >= 0x5100
+   /* __SUNPRO_C = 0xVRRP */
+#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12)
+#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF)
+#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_C    & 0xF)
+# else
+   /* __SUNPRO_CC = 0xVRP */
+#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8)
+#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF)
+#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_C    & 0xF)
+# endif
+
+#elif defined(__HP_cc)
+# define COMPILER_ID "HP"
+  /* __HP_cc = VVRRPP */
+# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000)
+# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100)
+# define COMPILER_VERSION_PATCH DEC(__HP_cc     % 100)
+
+#elif defined(__DECC)
+# define COMPILER_ID "Compaq"
+  /* __DECC_VER = VVRRTPPPP */
+# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000)
+# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000  % 100)
+# define COMPILER_VERSION_PATCH DEC(__DECC_VER         % 10000)
+
+#elif defined(__IBMC__) && defined(__COMPILER_VER__)
+# define COMPILER_ID "zOS"
+  /* __IBMC__ = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)
+
+#elif defined(__ibmxl__) && defined(__clang__)
+# define COMPILER_ID "XLClang"
+# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
+# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
+# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
+# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
+
+
+#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800
+# define COMPILER_ID "XL"
+  /* __IBMC__ = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)
+
+#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800
+# define COMPILER_ID "VisualAge"
+  /* __IBMC__ = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)
+
+#elif defined(__PGI)
+# define COMPILER_ID "PGI"
+# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
+# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
+# if defined(__PGIC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
+# endif
+
+#elif defined(_CRAYC)
+# define COMPILER_ID "Cray"
+# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
+# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
+
+#elif defined(__TI_COMPILER_VERSION__)
+# define COMPILER_ID "TI"
+  /* __TI_COMPILER_VERSION__ = VVVRRRPPP */
+# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
+# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000   % 1000)
+# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__        % 1000)
+
+#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version)
+# define COMPILER_ID "Fujitsu"
+
+#elif defined(__ghs__)
+# define COMPILER_ID "GHS"
+/* __GHS_VERSION_NUMBER = VVVVRP */
+# ifdef __GHS_VERSION_NUMBER
+# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
+# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER      % 10)
+# endif
+
+#elif defined(__TINYC__)
+# define COMPILER_ID "TinyCC"
+
+#elif defined(__BCC__)
+# define COMPILER_ID "Bruce"
+
+#elif defined(__SCO_VERSION__)
+# define COMPILER_ID "SCO"
+
+#elif defined(__ARMCC_VERSION) && !defined(__clang__)
+# define COMPILER_ID "ARMCC"
+#if __ARMCC_VERSION >= 1000000
+  /* __ARMCC_VERSION = VRRPPPP */
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
+  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
+  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION     % 10000)
+#else
+  /* __ARMCC_VERSION = VRPPPP */
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
+  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
+  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION    % 10000)
+#endif
+
+
+#elif defined(__clang__) && defined(__apple_build_version__)
+# define COMPILER_ID "AppleClang"
+# if defined(_MSC_VER)
+#  define SIMULATE_ID "MSVC"
+# endif
+# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
+# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
+# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
+# if defined(_MSC_VER)
+   /* _MSC_VER = VVRR */
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
+# endif
+# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
+
+#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
+# define COMPILER_ID "ARMClang"
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
+  # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
+  # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION     % 10000)
+# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
+
+#elif defined(__clang__)
+# define COMPILER_ID "Clang"
+# if defined(_MSC_VER)
+#  define SIMULATE_ID "MSVC"
+# endif
+# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
+# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
+# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
+# if defined(_MSC_VER)
+   /* _MSC_VER = VVRR */
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
+# endif
+
+#elif defined(__GNUC__)
+# define COMPILER_ID "GNU"
+# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
+# if defined(__GNUC_MINOR__)
+#  define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
+# endif
+
+#elif defined(_MSC_VER)
+# define COMPILER_ID "MSVC"
+  /* _MSC_VER = VVRR */
+# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
+# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
+# if defined(_MSC_FULL_VER)
+#  if _MSC_VER >= 1400
+    /* _MSC_FULL_VER = VVRRPPPPP */
+#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
+#  else
+    /* _MSC_FULL_VER = VVRRPPPP */
+#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
+#  endif
+# endif
+# if defined(_MSC_BUILD)
+#  define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
+# endif
+
+#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
+# define COMPILER_ID "ADSP"
+#if defined(__VISUALDSPVERSION__)
+  /* __VISUALDSPVERSION__ = 0xVVRRPP00 */
+# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
+# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
+# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8  & 0xFF)
+#endif
+
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
+# define COMPILER_ID "IAR"
+# if defined(__VER__) && defined(__ICCARM__)
+#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
+#  define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
+#  define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
+#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__))
+#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
+#  define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
+#  define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
+#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
+# endif
+
+#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC)
+# define COMPILER_ID "SDCC"
+# if defined(__SDCC_VERSION_MAJOR)
+#  define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR)
+#  define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR)
+#  define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH)
+# else
+  /* SDCC = VRP */
+#  define COMPILER_VERSION_MAJOR DEC(SDCC/100)
+#  define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10)
+#  define COMPILER_VERSION_PATCH DEC(SDCC    % 10)
+# endif
+
+
+/* These compilers are either not known or too old to define an
+  identification macro.  Try to identify the platform and guess that
+  it is the native compiler.  */
+#elif defined(__hpux) || defined(__hpua)
+# define COMPILER_ID "HP"
+
+#else /* unknown compiler */
+# define COMPILER_ID ""
+#endif
+
+/* Construct the string literal in pieces to prevent the source from
+   getting matched.  Store it in a pointer rather than an array
+   because some compilers will just produce instructions to fill the
+   array rather than assigning a pointer to a static array.  */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+#ifdef __QNXNTO__
+char const* qnxnto = "INFO" ":" "qnxnto[]";
+#endif
+
+#if defined(__CRAYXE) || defined(__CRAYXC)
+char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
+#endif
+
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+/* Identify known platforms by name.  */
+#if defined(__linux) || defined(__linux__) || defined(linux)
+# define PLATFORM_ID "Linux"
+
+#elif defined(__CYGWIN__)
+# define PLATFORM_ID "Cygwin"
+
+#elif defined(__MINGW32__)
+# define PLATFORM_ID "MinGW"
+
+#elif defined(__APPLE__)
+# define PLATFORM_ID "Darwin"
+
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+# define PLATFORM_ID "Windows"
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD)
+# define PLATFORM_ID "FreeBSD"
+
+#elif defined(__NetBSD__) || defined(__NetBSD)
+# define PLATFORM_ID "NetBSD"
+
+#elif defined(__OpenBSD__) || defined(__OPENBSD)
+# define PLATFORM_ID "OpenBSD"
+
+#elif defined(__sun) || defined(sun)
+# define PLATFORM_ID "SunOS"
+
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+# define PLATFORM_ID "AIX"
+
+#elif defined(__hpux) || defined(__hpux__)
+# define PLATFORM_ID "HP-UX"
+
+#elif defined(__HAIKU__)
+# define PLATFORM_ID "Haiku"
+
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
+# define PLATFORM_ID "BeOS"
+
+#elif defined(__QNX__) || defined(__QNXNTO__)
+# define PLATFORM_ID "QNX"
+
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
+# define PLATFORM_ID "Tru64"
+
+#elif defined(__riscos) || defined(__riscos__)
+# define PLATFORM_ID "RISCos"
+
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
+# define PLATFORM_ID "SINIX"
+
+#elif defined(__UNIX_SV__)
+# define PLATFORM_ID "UNIX_SV"
+
+#elif defined(__bsdos__)
+# define PLATFORM_ID "BSDOS"
+
+#elif defined(_MPRAS) || defined(MPRAS)
+# define PLATFORM_ID "MP-RAS"
+
+#elif defined(__osf) || defined(__osf__)
+# define PLATFORM_ID "OSF1"
+
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
+# define PLATFORM_ID "SCO_SV"
+
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
+# define PLATFORM_ID "ULTRIX"
+
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
+# define PLATFORM_ID "Xenix"
+
+#elif defined(__WATCOMC__)
+# if defined(__LINUX__)
+#  define PLATFORM_ID "Linux"
+
+# elif defined(__DOS__)
+#  define PLATFORM_ID "DOS"
+
+# elif defined(__OS2__)
+#  define PLATFORM_ID "OS2"
+
+# elif defined(__WINDOWS__)
+#  define PLATFORM_ID "Windows3x"
+
+# else /* unknown platform */
+#  define PLATFORM_ID
+# endif
+
+#elif defined(__INTEGRITY)
+# if defined(INT_178B)
+#  define PLATFORM_ID "Integrity178"
+
+# else /* regular Integrity */
+#  define PLATFORM_ID "Integrity"
+# endif
+
+#else /* unknown platform */
+# define PLATFORM_ID
+
+#endif
+
+/* For windows compilers MSVC and Intel we can determine
+   the architecture of the compiler being used.  This is because
+   the compilers do not have flags that can change the architecture,
+   but rather depend on which compiler is being used
+*/
+#if defined(_WIN32) && defined(_MSC_VER)
+# if defined(_M_IA64)
+#  define ARCHITECTURE_ID "IA64"
+
+# elif defined(_M_X64) || defined(_M_AMD64)
+#  define ARCHITECTURE_ID "x64"
+
+# elif defined(_M_IX86)
+#  define ARCHITECTURE_ID "X86"
+
+# elif defined(_M_ARM64)
+#  define ARCHITECTURE_ID "ARM64"
+
+# elif defined(_M_ARM)
+#  if _M_ARM == 4
+#   define ARCHITECTURE_ID "ARMV4I"
+#  elif _M_ARM == 5
+#   define ARCHITECTURE_ID "ARMV5I"
+#  else
+#   define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
+#  endif
+
+# elif defined(_M_MIPS)
+#  define ARCHITECTURE_ID "MIPS"
+
+# elif defined(_M_SH)
+#  define ARCHITECTURE_ID "SHx"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__WATCOMC__)
+# if defined(_M_I86)
+#  define ARCHITECTURE_ID "I86"
+
+# elif defined(_M_IX86)
+#  define ARCHITECTURE_ID "X86"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
+# if defined(__ICCARM__)
+#  define ARCHITECTURE_ID "ARM"
+
+# elif defined(__ICCRX__)
+#  define ARCHITECTURE_ID "RX"
+
+# elif defined(__ICCRH850__)
+#  define ARCHITECTURE_ID "RH850"
+
+# elif defined(__ICCRL78__)
+#  define ARCHITECTURE_ID "RL78"
+
+# elif defined(__ICCRISCV__)
+#  define ARCHITECTURE_ID "RISCV"
+
+# elif defined(__ICCAVR__)
+#  define ARCHITECTURE_ID "AVR"
+
+# elif defined(__ICC430__)
+#  define ARCHITECTURE_ID "MSP430"
+
+# elif defined(__ICCV850__)
+#  define ARCHITECTURE_ID "V850"
+
+# elif defined(__ICC8051__)
+#  define ARCHITECTURE_ID "8051"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__ghs__)
+# if defined(__PPC64__)
+#  define ARCHITECTURE_ID "PPC64"
+
+# elif defined(__ppc__)
+#  define ARCHITECTURE_ID "PPC"
+
+# elif defined(__ARM__)
+#  define ARCHITECTURE_ID "ARM"
+
+# elif defined(__x86_64__)
+#  define ARCHITECTURE_ID "x64"
+
+# elif defined(__i386__)
+#  define ARCHITECTURE_ID "X86"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+#else
+#  define ARCHITECTURE_ID
+#endif
+
+/* Convert integer to decimal digit literals.  */
+#define DEC(n)                   \
+  ('0' + (((n) / 10000000)%10)), \
+  ('0' + (((n) / 1000000)%10)),  \
+  ('0' + (((n) / 100000)%10)),   \
+  ('0' + (((n) / 10000)%10)),    \
+  ('0' + (((n) / 1000)%10)),     \
+  ('0' + (((n) / 100)%10)),      \
+  ('0' + (((n) / 10)%10)),       \
+  ('0' +  ((n) % 10))
+
+/* Convert integer to hex digit literals.  */
+#define HEX(n)             \
+  ('0' + ((n)>>28 & 0xF)), \
+  ('0' + ((n)>>24 & 0xF)), \
+  ('0' + ((n)>>20 & 0xF)), \
+  ('0' + ((n)>>16 & 0xF)), \
+  ('0' + ((n)>>12 & 0xF)), \
+  ('0' + ((n)>>8  & 0xF)), \
+  ('0' + ((n)>>4  & 0xF)), \
+  ('0' + ((n)     & 0xF))
+
+/* Construct a string literal encoding the version number components. */
+#ifdef COMPILER_VERSION_MAJOR
+char const info_version[] = {
+  'I', 'N', 'F', 'O', ':',
+  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
+  COMPILER_VERSION_MAJOR,
+# ifdef COMPILER_VERSION_MINOR
+  '.', COMPILER_VERSION_MINOR,
+#  ifdef COMPILER_VERSION_PATCH
+   '.', COMPILER_VERSION_PATCH,
+#   ifdef COMPILER_VERSION_TWEAK
+    '.', COMPILER_VERSION_TWEAK,
+#   endif
+#  endif
+# endif
+  ']','\0'};
+#endif
+
+/* Construct a string literal encoding the internal version number. */
+#ifdef COMPILER_VERSION_INTERNAL
+char const info_version_internal[] = {
+  'I', 'N', 'F', 'O', ':',
+  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
+  'i','n','t','e','r','n','a','l','[',
+  COMPILER_VERSION_INTERNAL,']','\0'};
+#endif
+
+/* Construct a string literal encoding the version number components. */
+#ifdef SIMULATE_VERSION_MAJOR
+char const info_simulate_version[] = {
+  'I', 'N', 'F', 'O', ':',
+  's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
+  SIMULATE_VERSION_MAJOR,
+# ifdef SIMULATE_VERSION_MINOR
+  '.', SIMULATE_VERSION_MINOR,
+#  ifdef SIMULATE_VERSION_PATCH
+   '.', SIMULATE_VERSION_PATCH,
+#   ifdef SIMULATE_VERSION_TWEAK
+    '.', SIMULATE_VERSION_TWEAK,
+#   endif
+#  endif
+# endif
+  ']','\0'};
+#endif
+
+/* Construct the string literal in pieces to prevent the source from
+   getting matched.  Store it in a pointer rather than an array
+   because some compilers will just produce instructions to fill the
+   array rather than assigning a pointer to a static array.  */
+char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
+char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
+
+
+
+
+#if !defined(__STDC__)
+# if (defined(_MSC_VER) && !defined(__clang__)) \
+  || (defined(__ibmxl__) || defined(__IBMC__))
+#  define C_DIALECT "90"
+# else
+#  define C_DIALECT
+# endif
+#elif __STDC_VERSION__ >= 201000L
+# define C_DIALECT "11"
+#elif __STDC_VERSION__ >= 199901L
+# define C_DIALECT "99"
+#else
+# define C_DIALECT "90"
+#endif
+const char* info_language_dialect_default =
+  "INFO" ":" "dialect_default[" C_DIALECT "]";
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef ID_VOID_MAIN
+void main() {}
+#else
+# if defined(__CLASSIC_C__)
+int main(argc, argv) int argc; char *argv[];
+# else
+int main(int argc, char* argv[])
+# endif
+{
+  int require = 0;
+  require += info_compiler[argc];
+  require += info_platform[argc];
+  require += info_arch[argc];
+#ifdef COMPILER_VERSION_MAJOR
+  require += info_version[argc];
+#endif
+#ifdef COMPILER_VERSION_INTERNAL
+  require += info_version_internal[argc];
+#endif
+#ifdef SIMULATE_ID
+  require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+  require += info_simulate_version[argc];
+#endif
+#if defined(__CRAYXE) || defined(__CRAYXC)
+  require += info_cray[argc];
+#endif
+  require += info_language_dialect_default[argc];
+  (void)argv;
+  return require;
+}
+#endif
diff --git a/API/.build/CMakeFiles/3.16.3/CompilerIdC/a.out b/API/.build/CMakeFiles/3.16.3/CompilerIdC/a.out
new file mode 100755
index 0000000000000000000000000000000000000000..46f1233d9a6b2e660d5d0c5fc3dbde0dfb7e863d
Binary files /dev/null and b/API/.build/CMakeFiles/3.16.3/CompilerIdC/a.out differ
diff --git a/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp b/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..69cfdba6bc7bccb09bf234388908de035caa0969
--- /dev/null
+++ b/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp
@@ -0,0 +1,660 @@
+/* This source file must have a .cpp extension so that all C++ compilers
+   recognize the extension without flags.  Borland does not know .cxx for
+   example.  */
+#ifndef __cplusplus
+# error "A C compiler has been selected for C++."
+#endif
+
+
+/* Version number components: V=Version, R=Revision, P=Patch
+   Version date components:   YYYY=Year, MM=Month,   DD=Day  */
+
+#if defined(__COMO__)
+# define COMPILER_ID "Comeau"
+  /* __COMO_VERSION__ = VRR */
+# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100)
+# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100)
+
+#elif defined(__INTEL_COMPILER) || defined(__ICC)
+# define COMPILER_ID "Intel"
+# if defined(_MSC_VER)
+#  define SIMULATE_ID "MSVC"
+# endif
+# if defined(__GNUC__)
+#  define SIMULATE_ID "GNU"
+# endif
+  /* __INTEL_COMPILER = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
+# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
+# if defined(__INTEL_COMPILER_UPDATE)
+#  define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
+# else
+#  define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER   % 10)
+# endif
+# if defined(__INTEL_COMPILER_BUILD_DATE)
+  /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
+#  define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
+# endif
+# if defined(_MSC_VER)
+   /* _MSC_VER = VVRR */
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
+# endif
+# if defined(__GNUC__)
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
+# elif defined(__GNUG__)
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
+# endif
+# if defined(__GNUC_MINOR__)
+#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+#  define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
+# endif
+
+#elif defined(__PATHCC__)
+# define COMPILER_ID "PathScale"
+# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
+# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
+# if defined(__PATHCC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
+# endif
+
+#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
+# define COMPILER_ID "Embarcadero"
+# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
+# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
+# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__     & 0xFFFF)
+
+#elif defined(__BORLANDC__)
+# define COMPILER_ID "Borland"
+  /* __BORLANDC__ = 0xVRR */
+# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
+# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
+
+#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
+# define COMPILER_ID "Watcom"
+   /* __WATCOMC__ = VVRR */
+# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
+# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
+# if (__WATCOMC__ % 10) > 0
+#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
+# endif
+
+#elif defined(__WATCOMC__)
+# define COMPILER_ID "OpenWatcom"
+   /* __WATCOMC__ = VVRP + 1100 */
+# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
+# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
+# if (__WATCOMC__ % 10) > 0
+#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
+# endif
+
+#elif defined(__SUNPRO_CC)
+# define COMPILER_ID "SunPro"
+# if __SUNPRO_CC >= 0x5100
+   /* __SUNPRO_CC = 0xVRRP */
+#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12)
+#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF)
+#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC    & 0xF)
+# else
+   /* __SUNPRO_CC = 0xVRP */
+#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8)
+#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF)
+#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC    & 0xF)
+# endif
+
+#elif defined(__HP_aCC)
+# define COMPILER_ID "HP"
+  /* __HP_aCC = VVRRPP */
+# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000)
+# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100)
+# define COMPILER_VERSION_PATCH DEC(__HP_aCC     % 100)
+
+#elif defined(__DECCXX)
+# define COMPILER_ID "Compaq"
+  /* __DECCXX_VER = VVRRTPPPP */
+# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000)
+# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000  % 100)
+# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER         % 10000)
+
+#elif defined(__IBMCPP__) && defined(__COMPILER_VER__)
+# define COMPILER_ID "zOS"
+  /* __IBMCPP__ = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)
+
+#elif defined(__ibmxl__) && defined(__clang__)
+# define COMPILER_ID "XLClang"
+# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
+# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
+# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
+# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
+
+
+#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800
+# define COMPILER_ID "XL"
+  /* __IBMCPP__ = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)
+
+#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800
+# define COMPILER_ID "VisualAge"
+  /* __IBMCPP__ = VRP */
+# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)
+
+#elif defined(__PGI)
+# define COMPILER_ID "PGI"
+# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
+# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
+# if defined(__PGIC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
+# endif
+
+#elif defined(_CRAYC)
+# define COMPILER_ID "Cray"
+# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
+# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
+
+#elif defined(__TI_COMPILER_VERSION__)
+# define COMPILER_ID "TI"
+  /* __TI_COMPILER_VERSION__ = VVVRRRPPP */
+# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
+# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000   % 1000)
+# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__        % 1000)
+
+#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version)
+# define COMPILER_ID "Fujitsu"
+
+#elif defined(__ghs__)
+# define COMPILER_ID "GHS"
+/* __GHS_VERSION_NUMBER = VVVVRP */
+# ifdef __GHS_VERSION_NUMBER
+# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
+# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER      % 10)
+# endif
+
+#elif defined(__SCO_VERSION__)
+# define COMPILER_ID "SCO"
+
+#elif defined(__ARMCC_VERSION) && !defined(__clang__)
+# define COMPILER_ID "ARMCC"
+#if __ARMCC_VERSION >= 1000000
+  /* __ARMCC_VERSION = VRRPPPP */
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
+  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
+  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION     % 10000)
+#else
+  /* __ARMCC_VERSION = VRPPPP */
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
+  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
+  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION    % 10000)
+#endif
+
+
+#elif defined(__clang__) && defined(__apple_build_version__)
+# define COMPILER_ID "AppleClang"
+# if defined(_MSC_VER)
+#  define SIMULATE_ID "MSVC"
+# endif
+# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
+# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
+# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
+# if defined(_MSC_VER)
+   /* _MSC_VER = VVRR */
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
+# endif
+# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
+
+#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
+# define COMPILER_ID "ARMClang"
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
+  # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
+  # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION     % 10000)
+# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
+
+#elif defined(__clang__)
+# define COMPILER_ID "Clang"
+# if defined(_MSC_VER)
+#  define SIMULATE_ID "MSVC"
+# endif
+# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
+# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
+# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
+# if defined(_MSC_VER)
+   /* _MSC_VER = VVRR */
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
+# endif
+
+#elif defined(__GNUC__) || defined(__GNUG__)
+# define COMPILER_ID "GNU"
+# if defined(__GNUC__)
+#  define COMPILER_VERSION_MAJOR DEC(__GNUC__)
+# else
+#  define COMPILER_VERSION_MAJOR DEC(__GNUG__)
+# endif
+# if defined(__GNUC_MINOR__)
+#  define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
+# endif
+
+#elif defined(_MSC_VER)
+# define COMPILER_ID "MSVC"
+  /* _MSC_VER = VVRR */
+# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
+# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
+# if defined(_MSC_FULL_VER)
+#  if _MSC_VER >= 1400
+    /* _MSC_FULL_VER = VVRRPPPPP */
+#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
+#  else
+    /* _MSC_FULL_VER = VVRRPPPP */
+#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
+#  endif
+# endif
+# if defined(_MSC_BUILD)
+#  define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
+# endif
+
+#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
+# define COMPILER_ID "ADSP"
+#if defined(__VISUALDSPVERSION__)
+  /* __VISUALDSPVERSION__ = 0xVVRRPP00 */
+# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
+# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
+# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8  & 0xFF)
+#endif
+
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
+# define COMPILER_ID "IAR"
+# if defined(__VER__) && defined(__ICCARM__)
+#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
+#  define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
+#  define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
+#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__))
+#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
+#  define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
+#  define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
+#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
+# endif
+
+
+/* These compilers are either not known or too old to define an
+  identification macro.  Try to identify the platform and guess that
+  it is the native compiler.  */
+#elif defined(__hpux) || defined(__hpua)
+# define COMPILER_ID "HP"
+
+#else /* unknown compiler */
+# define COMPILER_ID ""
+#endif
+
+/* Construct the string literal in pieces to prevent the source from
+   getting matched.  Store it in a pointer rather than an array
+   because some compilers will just produce instructions to fill the
+   array rather than assigning a pointer to a static array.  */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+#ifdef __QNXNTO__
+char const* qnxnto = "INFO" ":" "qnxnto[]";
+#endif
+
+#if defined(__CRAYXE) || defined(__CRAYXC)
+char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
+#endif
+
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+/* Identify known platforms by name.  */
+#if defined(__linux) || defined(__linux__) || defined(linux)
+# define PLATFORM_ID "Linux"
+
+#elif defined(__CYGWIN__)
+# define PLATFORM_ID "Cygwin"
+
+#elif defined(__MINGW32__)
+# define PLATFORM_ID "MinGW"
+
+#elif defined(__APPLE__)
+# define PLATFORM_ID "Darwin"
+
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+# define PLATFORM_ID "Windows"
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD)
+# define PLATFORM_ID "FreeBSD"
+
+#elif defined(__NetBSD__) || defined(__NetBSD)
+# define PLATFORM_ID "NetBSD"
+
+#elif defined(__OpenBSD__) || defined(__OPENBSD)
+# define PLATFORM_ID "OpenBSD"
+
+#elif defined(__sun) || defined(sun)
+# define PLATFORM_ID "SunOS"
+
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+# define PLATFORM_ID "AIX"
+
+#elif defined(__hpux) || defined(__hpux__)
+# define PLATFORM_ID "HP-UX"
+
+#elif defined(__HAIKU__)
+# define PLATFORM_ID "Haiku"
+
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
+# define PLATFORM_ID "BeOS"
+
+#elif defined(__QNX__) || defined(__QNXNTO__)
+# define PLATFORM_ID "QNX"
+
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
+# define PLATFORM_ID "Tru64"
+
+#elif defined(__riscos) || defined(__riscos__)
+# define PLATFORM_ID "RISCos"
+
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
+# define PLATFORM_ID "SINIX"
+
+#elif defined(__UNIX_SV__)
+# define PLATFORM_ID "UNIX_SV"
+
+#elif defined(__bsdos__)
+# define PLATFORM_ID "BSDOS"
+
+#elif defined(_MPRAS) || defined(MPRAS)
+# define PLATFORM_ID "MP-RAS"
+
+#elif defined(__osf) || defined(__osf__)
+# define PLATFORM_ID "OSF1"
+
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
+# define PLATFORM_ID "SCO_SV"
+
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
+# define PLATFORM_ID "ULTRIX"
+
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
+# define PLATFORM_ID "Xenix"
+
+#elif defined(__WATCOMC__)
+# if defined(__LINUX__)
+#  define PLATFORM_ID "Linux"
+
+# elif defined(__DOS__)
+#  define PLATFORM_ID "DOS"
+
+# elif defined(__OS2__)
+#  define PLATFORM_ID "OS2"
+
+# elif defined(__WINDOWS__)
+#  define PLATFORM_ID "Windows3x"
+
+# else /* unknown platform */
+#  define PLATFORM_ID
+# endif
+
+#elif defined(__INTEGRITY)
+# if defined(INT_178B)
+#  define PLATFORM_ID "Integrity178"
+
+# else /* regular Integrity */
+#  define PLATFORM_ID "Integrity"
+# endif
+
+#else /* unknown platform */
+# define PLATFORM_ID
+
+#endif
+
+/* For windows compilers MSVC and Intel we can determine
+   the architecture of the compiler being used.  This is because
+   the compilers do not have flags that can change the architecture,
+   but rather depend on which compiler is being used
+*/
+#if defined(_WIN32) && defined(_MSC_VER)
+# if defined(_M_IA64)
+#  define ARCHITECTURE_ID "IA64"
+
+# elif defined(_M_X64) || defined(_M_AMD64)
+#  define ARCHITECTURE_ID "x64"
+
+# elif defined(_M_IX86)
+#  define ARCHITECTURE_ID "X86"
+
+# elif defined(_M_ARM64)
+#  define ARCHITECTURE_ID "ARM64"
+
+# elif defined(_M_ARM)
+#  if _M_ARM == 4
+#   define ARCHITECTURE_ID "ARMV4I"
+#  elif _M_ARM == 5
+#   define ARCHITECTURE_ID "ARMV5I"
+#  else
+#   define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
+#  endif
+
+# elif defined(_M_MIPS)
+#  define ARCHITECTURE_ID "MIPS"
+
+# elif defined(_M_SH)
+#  define ARCHITECTURE_ID "SHx"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__WATCOMC__)
+# if defined(_M_I86)
+#  define ARCHITECTURE_ID "I86"
+
+# elif defined(_M_IX86)
+#  define ARCHITECTURE_ID "X86"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
+# if defined(__ICCARM__)
+#  define ARCHITECTURE_ID "ARM"
+
+# elif defined(__ICCRX__)
+#  define ARCHITECTURE_ID "RX"
+
+# elif defined(__ICCRH850__)
+#  define ARCHITECTURE_ID "RH850"
+
+# elif defined(__ICCRL78__)
+#  define ARCHITECTURE_ID "RL78"
+
+# elif defined(__ICCRISCV__)
+#  define ARCHITECTURE_ID "RISCV"
+
+# elif defined(__ICCAVR__)
+#  define ARCHITECTURE_ID "AVR"
+
+# elif defined(__ICC430__)
+#  define ARCHITECTURE_ID "MSP430"
+
+# elif defined(__ICCV850__)
+#  define ARCHITECTURE_ID "V850"
+
+# elif defined(__ICC8051__)
+#  define ARCHITECTURE_ID "8051"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__ghs__)
+# if defined(__PPC64__)
+#  define ARCHITECTURE_ID "PPC64"
+
+# elif defined(__ppc__)
+#  define ARCHITECTURE_ID "PPC"
+
+# elif defined(__ARM__)
+#  define ARCHITECTURE_ID "ARM"
+
+# elif defined(__x86_64__)
+#  define ARCHITECTURE_ID "x64"
+
+# elif defined(__i386__)
+#  define ARCHITECTURE_ID "X86"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+#else
+#  define ARCHITECTURE_ID
+#endif
+
+/* Convert integer to decimal digit literals.  */
+#define DEC(n)                   \
+  ('0' + (((n) / 10000000)%10)), \
+  ('0' + (((n) / 1000000)%10)),  \
+  ('0' + (((n) / 100000)%10)),   \
+  ('0' + (((n) / 10000)%10)),    \
+  ('0' + (((n) / 1000)%10)),     \
+  ('0' + (((n) / 100)%10)),      \
+  ('0' + (((n) / 10)%10)),       \
+  ('0' +  ((n) % 10))
+
+/* Convert integer to hex digit literals.  */
+#define HEX(n)             \
+  ('0' + ((n)>>28 & 0xF)), \
+  ('0' + ((n)>>24 & 0xF)), \
+  ('0' + ((n)>>20 & 0xF)), \
+  ('0' + ((n)>>16 & 0xF)), \
+  ('0' + ((n)>>12 & 0xF)), \
+  ('0' + ((n)>>8  & 0xF)), \
+  ('0' + ((n)>>4  & 0xF)), \
+  ('0' + ((n)     & 0xF))
+
+/* Construct a string literal encoding the version number components. */
+#ifdef COMPILER_VERSION_MAJOR
+char const info_version[] = {
+  'I', 'N', 'F', 'O', ':',
+  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
+  COMPILER_VERSION_MAJOR,
+# ifdef COMPILER_VERSION_MINOR
+  '.', COMPILER_VERSION_MINOR,
+#  ifdef COMPILER_VERSION_PATCH
+   '.', COMPILER_VERSION_PATCH,
+#   ifdef COMPILER_VERSION_TWEAK
+    '.', COMPILER_VERSION_TWEAK,
+#   endif
+#  endif
+# endif
+  ']','\0'};
+#endif
+
+/* Construct a string literal encoding the internal version number. */
+#ifdef COMPILER_VERSION_INTERNAL
+char const info_version_internal[] = {
+  'I', 'N', 'F', 'O', ':',
+  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
+  'i','n','t','e','r','n','a','l','[',
+  COMPILER_VERSION_INTERNAL,']','\0'};
+#endif
+
+/* Construct a string literal encoding the version number components. */
+#ifdef SIMULATE_VERSION_MAJOR
+char const info_simulate_version[] = {
+  'I', 'N', 'F', 'O', ':',
+  's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
+  SIMULATE_VERSION_MAJOR,
+# ifdef SIMULATE_VERSION_MINOR
+  '.', SIMULATE_VERSION_MINOR,
+#  ifdef SIMULATE_VERSION_PATCH
+   '.', SIMULATE_VERSION_PATCH,
+#   ifdef SIMULATE_VERSION_TWEAK
+    '.', SIMULATE_VERSION_TWEAK,
+#   endif
+#  endif
+# endif
+  ']','\0'};
+#endif
+
+/* Construct the string literal in pieces to prevent the source from
+   getting matched.  Store it in a pointer rather than an array
+   because some compilers will just produce instructions to fill the
+   array rather than assigning a pointer to a static array.  */
+char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
+char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
+
+
+
+
+#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L
+#  if defined(__INTEL_CXX11_MODE__)
+#    if defined(__cpp_aggregate_nsdmi)
+#      define CXX_STD 201402L
+#    else
+#      define CXX_STD 201103L
+#    endif
+#  else
+#    define CXX_STD 199711L
+#  endif
+#elif defined(_MSC_VER) && defined(_MSVC_LANG)
+#  define CXX_STD _MSVC_LANG
+#else
+#  define CXX_STD __cplusplus
+#endif
+
+const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+#if CXX_STD > 201703L
+  "20"
+#elif CXX_STD >= 201703L
+  "17"
+#elif CXX_STD >= 201402L
+  "14"
+#elif CXX_STD >= 201103L
+  "11"
+#else
+  "98"
+#endif
+"]";
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char* argv[])
+{
+  int require = 0;
+  require += info_compiler[argc];
+  require += info_platform[argc];
+#ifdef COMPILER_VERSION_MAJOR
+  require += info_version[argc];
+#endif
+#ifdef COMPILER_VERSION_INTERNAL
+  require += info_version_internal[argc];
+#endif
+#ifdef SIMULATE_ID
+  require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+  require += info_simulate_version[argc];
+#endif
+#if defined(__CRAYXE) || defined(__CRAYXC)
+  require += info_cray[argc];
+#endif
+  require += info_language_dialect_default[argc];
+  (void)argv;
+  return require;
+}
diff --git a/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/a.out b/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/a.out
new file mode 100755
index 0000000000000000000000000000000000000000..c8684265455284359fc556a1ef0b98aa7a612508
Binary files /dev/null and b/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/a.out differ
diff --git a/API/.build/CMakeFiles/CMakeDirectoryInformation.cmake b/API/.build/CMakeFiles/CMakeDirectoryInformation.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..4c28209e2e10747c575d165e253f954c094c36cc
--- /dev/null
+++ b/API/.build/CMakeFiles/CMakeDirectoryInformation.cmake
@@ -0,0 +1,16 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# Relative path conversion top directories.
+set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/tingjie/src/operating-system/API")
+set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/tingjie/src/operating-system/API/.build")
+
+# Force unix paths in dependencies.
+set(CMAKE_FORCE_UNIX_PATHS 1)
+
+
+# The C and CXX include file regular expressions for this directory.
+set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$")
+set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$")
+set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})
+set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN})
diff --git a/API/.build/CMakeFiles/CMakeOutput.log b/API/.build/CMakeFiles/CMakeOutput.log
new file mode 100644
index 0000000000000000000000000000000000000000..3d10153fa8ebac9e7888caaa1e7f36ff432a733f
--- /dev/null
+++ b/API/.build/CMakeFiles/CMakeOutput.log
@@ -0,0 +1,463 @@
+The system is: Linux - 5.4.0-86-generic - x86_64
+Compiling the C compiler identification source file "CMakeCCompilerId.c" succeeded.
+Compiler: /usr/bin/cc 
+Build flags: 
+Id flags:  
+
+The output was:
+0
+
+
+Compilation of the C compiler identification source "CMakeCCompilerId.c" produced "a.out"
+
+The C compiler identification is GNU, found in "/home/tingjie/src/operating-system/API/.build/CMakeFiles/3.16.3/CompilerIdC/a.out"
+
+Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded.
+Compiler: /usr/bin/c++ 
+Build flags: 
+Id flags:  
+
+The output was:
+0
+
+
+Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.out"
+
+The CXX compiler identification is GNU, found in "/home/tingjie/src/operating-system/API/.build/CMakeFiles/3.16.3/CompilerIdCXX/a.out"
+
+Determining if the C compiler works passed with the following output:
+Change Dir: /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/make cmTC_73eb4/fast && /usr/bin/make -f CMakeFiles/cmTC_73eb4.dir/build.make CMakeFiles/cmTC_73eb4.dir/build
+make[1]: Entering directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Building C object CMakeFiles/cmTC_73eb4.dir/testCCompiler.c.o
+/usr/bin/cc    -o CMakeFiles/cmTC_73eb4.dir/testCCompiler.c.o   -c /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp/testCCompiler.c
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Linking C executable cmTC_73eb4
+/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_73eb4.dir/link.txt --verbose=1
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+/usr/bin/cc    -static  CMakeFiles/cmTC_73eb4.dir/testCCompiler.c.o  -o cmTC_73eb4 
+make[1]: Leaving directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+
+
+
+Detecting C compiler ABI info compiled with the following output:
+Change Dir: /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/make cmTC_c9e46/fast && /usr/bin/make -f CMakeFiles/cmTC_c9e46.dir/build.make CMakeFiles/cmTC_c9e46.dir/build
+make[1]: Entering directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Building C object CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o
+/usr/bin/cc   -v -o CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o   -c /usr/share/cmake-3.16/Modules/CMakeCCompilerABI.c
+Using built-in specs.
+COLLECT_GCC=/usr/bin/cc
+OFFLOAD_TARGET_NAMES=nvptx-none:hsa
+OFFLOAD_TARGET_DEFAULT=1
+Target: x86_64-linux-gnu
+Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
+Thread model: posix
+gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) 
+COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64'
+ /usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu /usr/share/cmake-3.16/Modules/CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mtune=generic -march=x86-64 -auxbase-strip CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccImgnGs.s
+GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
+	compiled by GNU C version 9.3.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP
+
+GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
+ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
+ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
+ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
+#include "..." search starts here:
+#include <...> search starts here:
+ /usr/lib/gcc/x86_64-linux-gnu/9/include
+ /usr/local/include
+ /usr/include/x86_64-linux-gnu
+ /usr/include
+End of search list.
+GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
+	compiled by GNU C version 9.3.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP
+
+GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
+Compiler executable checksum: bbf13931d8de1abe14040c9909cb6969
+COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64'
+ as -v --64 -o CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o /tmp/ccImgnGs.s
+GNU assembler version 2.34 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.34
+COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/
+LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/
+COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64'
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Linking C executable cmTC_c9e46
+/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_c9e46.dir/link.txt --verbose=1
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+/usr/bin/cc    -static -v CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o  -o cmTC_c9e46 
+Using built-in specs.
+COLLECT_GCC=/usr/bin/cc
+COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
+OFFLOAD_TARGET_NAMES=nvptx-none:hsa
+OFFLOAD_TARGET_DEFAULT=1
+Target: x86_64-linux-gnu
+Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
+Thread model: posix
+gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) 
+COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/
+LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/
+COLLECT_GCC_OPTIONS='-static' '-v' '-o' 'cmTC_c9e46' '-mtune=generic' '-march=x86-64'
+ /usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/cc9MZioX.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o cmTC_c9e46 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
+COLLECT_GCC_OPTIONS='-static' '-v' '-o' 'cmTC_c9e46' '-mtune=generic' '-march=x86-64'
+make[1]: Leaving directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+
+
+
+Parsed C implicit include dir info from above output: rv=done
+  found start of include info
+  found start of implicit include info
+    add: [/usr/lib/gcc/x86_64-linux-gnu/9/include]
+    add: [/usr/local/include]
+    add: [/usr/include/x86_64-linux-gnu]
+    add: [/usr/include]
+  end of search list found
+  collapse include dir [/usr/lib/gcc/x86_64-linux-gnu/9/include] ==> [/usr/lib/gcc/x86_64-linux-gnu/9/include]
+  collapse include dir [/usr/local/include] ==> [/usr/local/include]
+  collapse include dir [/usr/include/x86_64-linux-gnu] ==> [/usr/include/x86_64-linux-gnu]
+  collapse include dir [/usr/include] ==> [/usr/include]
+  implicit include dirs: [/usr/lib/gcc/x86_64-linux-gnu/9/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include]
+
+
+Parsed C implicit link information from above output:
+  link line regex: [^( *|.*[/\])(ld|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\]+-)?ld|collect2)[^/\]*( |$)]
+  ignore line: [Change Dir: /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp]
+  ignore line: []
+  ignore line: [Run Build Command(s):/usr/bin/make cmTC_c9e46/fast && /usr/bin/make -f CMakeFiles/cmTC_c9e46.dir/build.make CMakeFiles/cmTC_c9e46.dir/build]
+  ignore line: [make[1]: Entering directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp']
+  ignore line: [/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)]
+  ignore line: [Building C object CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o]
+  ignore line: [/usr/bin/cc   -v -o CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o   -c /usr/share/cmake-3.16/Modules/CMakeCCompilerABI.c]
+  ignore line: [Using built-in specs.]
+  ignore line: [COLLECT_GCC=/usr/bin/cc]
+  ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:hsa]
+  ignore line: [OFFLOAD_TARGET_DEFAULT=1]
+  ignore line: [Target: x86_64-linux-gnu]
+  ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c ada c++ go brig d fortran objc obj-c++ gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
+  ignore line: [Thread model: posix]
+  ignore line: [gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) ]
+  ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64']
+  ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu /usr/share/cmake-3.16/Modules/CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mtune=generic -march=x86-64 -auxbase-strip CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccImgnGs.s]
+  ignore line: [GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)]
+  ignore line: [	compiled by GNU C version 9.3.0  GMP version 6.2.0  MPFR version 4.0.2  MPC version 1.1.0  isl version isl-0.22.1-GMP]
+  ignore line: []
+  ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
+  ignore line: [ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"]
+  ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"]
+  ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"]
+  ignore line: [#include "..." search starts here:]
+  ignore line: [#include <...> search starts here:]
+  ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/9/include]
+  ignore line: [ /usr/local/include]
+  ignore line: [ /usr/include/x86_64-linux-gnu]
+  ignore line: [ /usr/include]
+  ignore line: [End of search list.]
+  ignore line: [GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)]
+  ignore line: [	compiled by GNU C version 9.3.0  GMP version 6.2.0  MPFR version 4.0.2  MPC version 1.1.0  isl version isl-0.22.1-GMP]
+  ignore line: []
+  ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
+  ignore line: [Compiler executable checksum: bbf13931d8de1abe14040c9909cb6969]
+  ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64']
+  ignore line: [ as -v --64 -o CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o /tmp/ccImgnGs.s]
+  ignore line: [GNU assembler version 2.34 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.34]
+  ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/]
+  ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/]
+  ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64']
+  ignore line: [/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)]
+  ignore line: [Linking C executable cmTC_c9e46]
+  ignore line: [/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_c9e46.dir/link.txt --verbose=1]
+  ignore line: [/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)]
+  ignore line: [/usr/bin/cc    -static -v CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o  -o cmTC_c9e46 ]
+  ignore line: [Using built-in specs.]
+  ignore line: [COLLECT_GCC=/usr/bin/cc]
+  ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper]
+  ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:hsa]
+  ignore line: [OFFLOAD_TARGET_DEFAULT=1]
+  ignore line: [Target: x86_64-linux-gnu]
+  ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c ada c++ go brig d fortran objc obj-c++ gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
+  ignore line: [Thread model: posix]
+  ignore line: [gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) ]
+  ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/]
+  ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/]
+  ignore line: [COLLECT_GCC_OPTIONS='-static' '-v' '-o' 'cmTC_c9e46' '-mtune=generic' '-march=x86-64']
+  link line: [ /usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/cc9MZioX.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o cmTC_c9e46 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o]
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/collect2] ==> ignore
+    arg [-plugin] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so] ==> ignore
+    arg [-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper] ==> ignore
+    arg [-plugin-opt=-fresolution=/tmp/cc9MZioX.res] ==> ignore
+    arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
+    arg [-plugin-opt=-pass-through=-lgcc_eh] ==> ignore
+    arg [-plugin-opt=-pass-through=-lc] ==> ignore
+    arg [--build-id] ==> ignore
+    arg [-m] ==> ignore
+    arg [elf_x86_64] ==> ignore
+    arg [--hash-style=gnu] ==> ignore
+    arg [--as-needed] ==> ignore
+    arg [-static] ==> ignore
+    arg [-zrelro] ==> ignore
+    arg [-o] ==> ignore
+    arg [cmTC_c9e46] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o] ==> ignore
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9]
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu]
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib]
+    arg [-L/lib/x86_64-linux-gnu] ==> dir [/lib/x86_64-linux-gnu]
+    arg [-L/lib/../lib] ==> dir [/lib/../lib]
+    arg [-L/usr/lib/x86_64-linux-gnu] ==> dir [/usr/lib/x86_64-linux-gnu]
+    arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib]
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9/../../..] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../..]
+    arg [CMakeFiles/cmTC_c9e46.dir/CMakeCCompilerABI.c.o] ==> ignore
+    arg [--start-group] ==> ignore
+    arg [-lgcc] ==> lib [gcc]
+    arg [-lgcc_eh] ==> lib [gcc_eh]
+    arg [-lc] ==> lib [c]
+    arg [--end-group] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o] ==> ignore
+  remove lib [gcc_eh]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9] ==> [/usr/lib/gcc/x86_64-linux-gnu/9]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib] ==> [/usr/lib]
+  collapse library dir [/lib/x86_64-linux-gnu] ==> [/lib/x86_64-linux-gnu]
+  collapse library dir [/lib/../lib] ==> [/lib]
+  collapse library dir [/usr/lib/x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
+  collapse library dir [/usr/lib/../lib] ==> [/usr/lib]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../..] ==> [/usr/lib]
+  implicit libs: [gcc;c]
+  implicit dirs: [/usr/lib/gcc/x86_64-linux-gnu/9;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib]
+  implicit fwks: []
+
+
+Determining if the CXX compiler works passed with the following output:
+Change Dir: /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/make cmTC_d24db/fast && /usr/bin/make -f CMakeFiles/cmTC_d24db.dir/build.make CMakeFiles/cmTC_d24db.dir/build
+make[1]: Entering directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Building CXX object CMakeFiles/cmTC_d24db.dir/testCXXCompiler.cxx.o
+/usr/bin/c++    -std=gnu++17 -o CMakeFiles/cmTC_d24db.dir/testCXXCompiler.cxx.o -c /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp/testCXXCompiler.cxx
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Linking CXX executable cmTC_d24db
+/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_d24db.dir/link.txt --verbose=1
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+/usr/bin/c++     -static  CMakeFiles/cmTC_d24db.dir/testCXXCompiler.cxx.o  -o cmTC_d24db 
+make[1]: Leaving directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+
+
+
+Detecting CXX compiler ABI info compiled with the following output:
+Change Dir: /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/make cmTC_50327/fast && /usr/bin/make -f CMakeFiles/cmTC_50327.dir/build.make CMakeFiles/cmTC_50327.dir/build
+make[1]: Entering directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Building CXX object CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o
+/usr/bin/c++    -v -std=gnu++17 -o CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-3.16/Modules/CMakeCXXCompilerABI.cpp
+Using built-in specs.
+COLLECT_GCC=/usr/bin/c++
+OFFLOAD_TARGET_NAMES=nvptx-none:hsa
+OFFLOAD_TARGET_DEFAULT=1
+Target: x86_64-linux-gnu
+Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
+Thread model: posix
+gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) 
+COLLECT_GCC_OPTIONS='-v' '-std=gnu++17' '-o' 'CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
+ /usr/lib/gcc/x86_64-linux-gnu/9/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /usr/share/cmake-3.16/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mtune=generic -march=x86-64 -auxbase-strip CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o -std=gnu++17 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccXjblus.s
+GNU C++17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
+	compiled by GNU C version 9.3.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP
+
+GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
+ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/9"
+ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
+ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
+ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
+#include "..." search starts here:
+#include <...> search starts here:
+ /usr/include/c++/9
+ /usr/include/x86_64-linux-gnu/c++/9
+ /usr/include/c++/9/backward
+ /usr/lib/gcc/x86_64-linux-gnu/9/include
+ /usr/local/include
+ /usr/include/x86_64-linux-gnu
+ /usr/include
+End of search list.
+GNU C++17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
+	compiled by GNU C version 9.3.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP
+
+GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
+Compiler executable checksum: 466f818abe2f30ba03783f22bd12d815
+COLLECT_GCC_OPTIONS='-v' '-std=gnu++17' '-o' 'CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
+ as -v --64 -o CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccXjblus.s
+GNU assembler version 2.34 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.34
+COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/
+LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/
+COLLECT_GCC_OPTIONS='-v' '-std=gnu++17' '-o' 'CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+Linking CXX executable cmTC_50327
+/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_50327.dir/link.txt --verbose=1
+/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)
+/usr/bin/c++     -static -v CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o  -o cmTC_50327 
+Using built-in specs.
+COLLECT_GCC=/usr/bin/c++
+COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
+OFFLOAD_TARGET_NAMES=nvptx-none:hsa
+OFFLOAD_TARGET_DEFAULT=1
+Target: x86_64-linux-gnu
+Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
+Thread model: posix
+gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) 
+COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/
+LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/
+COLLECT_GCC_OPTIONS='-static' '-v' '-o' 'cmTC_50327' '-mtune=generic' '-march=x86-64'
+ /usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccnhI7WV.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o cmTC_50327 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
+COLLECT_GCC_OPTIONS='-static' '-v' '-o' 'cmTC_50327' '-mtune=generic' '-march=x86-64'
+make[1]: Leaving directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp'
+
+
+
+Parsed CXX implicit include dir info from above output: rv=done
+  found start of include info
+  found start of implicit include info
+    add: [/usr/include/c++/9]
+    add: [/usr/include/x86_64-linux-gnu/c++/9]
+    add: [/usr/include/c++/9/backward]
+    add: [/usr/lib/gcc/x86_64-linux-gnu/9/include]
+    add: [/usr/local/include]
+    add: [/usr/include/x86_64-linux-gnu]
+    add: [/usr/include]
+  end of search list found
+  collapse include dir [/usr/include/c++/9] ==> [/usr/include/c++/9]
+  collapse include dir [/usr/include/x86_64-linux-gnu/c++/9] ==> [/usr/include/x86_64-linux-gnu/c++/9]
+  collapse include dir [/usr/include/c++/9/backward] ==> [/usr/include/c++/9/backward]
+  collapse include dir [/usr/lib/gcc/x86_64-linux-gnu/9/include] ==> [/usr/lib/gcc/x86_64-linux-gnu/9/include]
+  collapse include dir [/usr/local/include] ==> [/usr/local/include]
+  collapse include dir [/usr/include/x86_64-linux-gnu] ==> [/usr/include/x86_64-linux-gnu]
+  collapse include dir [/usr/include] ==> [/usr/include]
+  implicit include dirs: [/usr/include/c++/9;/usr/include/x86_64-linux-gnu/c++/9;/usr/include/c++/9/backward;/usr/lib/gcc/x86_64-linux-gnu/9/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include]
+
+
+Parsed CXX implicit link information from above output:
+  link line regex: [^( *|.*[/\])(ld|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\]+-)?ld|collect2)[^/\]*( |$)]
+  ignore line: [Change Dir: /home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp]
+  ignore line: []
+  ignore line: [Run Build Command(s):/usr/bin/make cmTC_50327/fast && /usr/bin/make -f CMakeFiles/cmTC_50327.dir/build.make CMakeFiles/cmTC_50327.dir/build]
+  ignore line: [make[1]: Entering directory '/home/tingjie/src/operating-system/API/.build/CMakeFiles/CMakeTmp']
+  ignore line: [/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)]
+  ignore line: [Building CXX object CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o]
+  ignore line: [/usr/bin/c++    -v -std=gnu++17 -o CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-3.16/Modules/CMakeCXXCompilerABI.cpp]
+  ignore line: [Using built-in specs.]
+  ignore line: [COLLECT_GCC=/usr/bin/c++]
+  ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:hsa]
+  ignore line: [OFFLOAD_TARGET_DEFAULT=1]
+  ignore line: [Target: x86_64-linux-gnu]
+  ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c ada c++ go brig d fortran objc obj-c++ gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
+  ignore line: [Thread model: posix]
+  ignore line: [gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) ]
+  ignore line: [COLLECT_GCC_OPTIONS='-v' '-std=gnu++17' '-o' 'CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64']
+  ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/9/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /usr/share/cmake-3.16/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mtune=generic -march=x86-64 -auxbase-strip CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o -std=gnu++17 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccXjblus.s]
+  ignore line: [GNU C++17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)]
+  ignore line: [	compiled by GNU C version 9.3.0  GMP version 6.2.0  MPFR version 4.0.2  MPC version 1.1.0  isl version isl-0.22.1-GMP]
+  ignore line: []
+  ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
+  ignore line: [ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/9"]
+  ignore line: [ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"]
+  ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"]
+  ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"]
+  ignore line: [#include "..." search starts here:]
+  ignore line: [#include <...> search starts here:]
+  ignore line: [ /usr/include/c++/9]
+  ignore line: [ /usr/include/x86_64-linux-gnu/c++/9]
+  ignore line: [ /usr/include/c++/9/backward]
+  ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/9/include]
+  ignore line: [ /usr/local/include]
+  ignore line: [ /usr/include/x86_64-linux-gnu]
+  ignore line: [ /usr/include]
+  ignore line: [End of search list.]
+  ignore line: [GNU C++17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)]
+  ignore line: [	compiled by GNU C version 9.3.0  GMP version 6.2.0  MPFR version 4.0.2  MPC version 1.1.0  isl version isl-0.22.1-GMP]
+  ignore line: []
+  ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
+  ignore line: [Compiler executable checksum: 466f818abe2f30ba03783f22bd12d815]
+  ignore line: [COLLECT_GCC_OPTIONS='-v' '-std=gnu++17' '-o' 'CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64']
+  ignore line: [ as -v --64 -o CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccXjblus.s]
+  ignore line: [GNU assembler version 2.34 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.34]
+  ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/]
+  ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/]
+  ignore line: [COLLECT_GCC_OPTIONS='-v' '-std=gnu++17' '-o' 'CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64']
+  ignore line: [/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)]
+  ignore line: [Linking CXX executable cmTC_50327]
+  ignore line: [/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_50327.dir/link.txt --verbose=1]
+  ignore line: [/usr/bin/cmake: /usr/local/lib/libcurl.so.4: no version information available (required by /usr/bin/cmake)]
+  ignore line: [/usr/bin/c++     -static -v CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o  -o cmTC_50327 ]
+  ignore line: [Using built-in specs.]
+  ignore line: [COLLECT_GCC=/usr/bin/c++]
+  ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper]
+  ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:hsa]
+  ignore line: [OFFLOAD_TARGET_DEFAULT=1]
+  ignore line: [Target: x86_64-linux-gnu]
+  ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c ada c++ go brig d fortran objc obj-c++ gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
+  ignore line: [Thread model: posix]
+  ignore line: [gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) ]
+  ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/]
+  ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/]
+  ignore line: [COLLECT_GCC_OPTIONS='-static' '-v' '-o' 'cmTC_50327' '-mtune=generic' '-march=x86-64']
+  link line: [ /usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccnhI7WV.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o cmTC_50327 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o]
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/collect2] ==> ignore
+    arg [-plugin] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so] ==> ignore
+    arg [-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper] ==> ignore
+    arg [-plugin-opt=-fresolution=/tmp/ccnhI7WV.res] ==> ignore
+    arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
+    arg [-plugin-opt=-pass-through=-lgcc_eh] ==> ignore
+    arg [-plugin-opt=-pass-through=-lc] ==> ignore
+    arg [--build-id] ==> ignore
+    arg [-m] ==> ignore
+    arg [elf_x86_64] ==> ignore
+    arg [--hash-style=gnu] ==> ignore
+    arg [--as-needed] ==> ignore
+    arg [-static] ==> ignore
+    arg [-zrelro] ==> ignore
+    arg [-o] ==> ignore
+    arg [cmTC_50327] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o] ==> ignore
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9]
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu]
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib]
+    arg [-L/lib/x86_64-linux-gnu] ==> dir [/lib/x86_64-linux-gnu]
+    arg [-L/lib/../lib] ==> dir [/lib/../lib]
+    arg [-L/usr/lib/x86_64-linux-gnu] ==> dir [/usr/lib/x86_64-linux-gnu]
+    arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib]
+    arg [-L/usr/lib/gcc/x86_64-linux-gnu/9/../../..] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../..]
+    arg [CMakeFiles/cmTC_50327.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore
+    arg [-lstdc++] ==> lib [stdc++]
+    arg [-lm] ==> lib [m]
+    arg [--start-group] ==> ignore
+    arg [-lgcc] ==> lib [gcc]
+    arg [-lgcc_eh] ==> lib [gcc_eh]
+    arg [-lc] ==> lib [c]
+    arg [--end-group] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o] ==> ignore
+    arg [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o] ==> ignore
+  remove lib [gcc_eh]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9] ==> [/usr/lib/gcc/x86_64-linux-gnu/9]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib] ==> [/usr/lib]
+  collapse library dir [/lib/x86_64-linux-gnu] ==> [/lib/x86_64-linux-gnu]
+  collapse library dir [/lib/../lib] ==> [/lib]
+  collapse library dir [/usr/lib/x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
+  collapse library dir [/usr/lib/../lib] ==> [/usr/lib]
+  collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/9/../../..] ==> [/usr/lib]
+  implicit libs: [stdc++;m;gcc;c]
+  implicit dirs: [/usr/lib/gcc/x86_64-linux-gnu/9;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib]
+  implicit fwks: []
+
+
diff --git a/API/.build/CMakeFiles/Makefile.cmake b/API/.build/CMakeFiles/Makefile.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..7d4a8bba02cbeda6aaf947456f2260aba6e0618c
--- /dev/null
+++ b/API/.build/CMakeFiles/Makefile.cmake
@@ -0,0 +1,51 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# The generator used is:
+set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles")
+
+# The top level Makefile was generated from the following files:
+set(CMAKE_MAKEFILE_DEPENDS
+  "CMakeCache.txt"
+  "CMakeFiles/3.16.3/CMakeCCompiler.cmake"
+  "CMakeFiles/3.16.3/CMakeCXXCompiler.cmake"
+  "CMakeFiles/3.16.3/CMakeSystem.cmake"
+  "../CMakeLists.txt"
+  "../version.h.in"
+  "/usr/share/cmake-3.16/Modules/CMakeCInformation.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeCXXInformation.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeCommonLanguageInclude.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeGenericSystem.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeInitializeConfigs.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeLanguageInformation.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeSystemSpecificInformation.cmake"
+  "/usr/share/cmake-3.16/Modules/CMakeSystemSpecificInitialize.cmake"
+  "/usr/share/cmake-3.16/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
+  "/usr/share/cmake-3.16/Modules/Compiler/GNU-C.cmake"
+  "/usr/share/cmake-3.16/Modules/Compiler/GNU-CXX.cmake"
+  "/usr/share/cmake-3.16/Modules/Compiler/GNU.cmake"
+  "/usr/share/cmake-3.16/Modules/Internal/CMakeCheckCompilerFlag.cmake"
+  "/usr/share/cmake-3.16/Modules/Platform/Linux-GNU-C.cmake"
+  "/usr/share/cmake-3.16/Modules/Platform/Linux-GNU-CXX.cmake"
+  "/usr/share/cmake-3.16/Modules/Platform/Linux-GNU.cmake"
+  "/usr/share/cmake-3.16/Modules/Platform/Linux.cmake"
+  "/usr/share/cmake-3.16/Modules/Platform/UnixPaths.cmake"
+  )
+
+# The corresponding makefile is:
+set(CMAKE_MAKEFILE_OUTPUTS
+  "Makefile"
+  "CMakeFiles/cmake.check_cache"
+  )
+
+# Byproducts of CMake generate step:
+set(CMAKE_MAKEFILE_PRODUCTS
+  "snakeoil_version.h"
+  "CMakeFiles/CMakeDirectoryInformation.cmake"
+  )
+
+# Dependency information for all targets:
+set(CMAKE_DEPEND_INFO_FILES
+  "CMakeFiles/snakeoil_api.dir/DependInfo.cmake"
+  )
diff --git a/API/.build/CMakeFiles/Makefile2 b/API/.build/CMakeFiles/Makefile2
new file mode 100644
index 0000000000000000000000000000000000000000..d8b4f0f33f5410b82a793ea522faa98480f7964e
--- /dev/null
+++ b/API/.build/CMakeFiles/Makefile2
@@ -0,0 +1,106 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# Default target executed when no arguments are given to make.
+default_target: all
+
+.PHONY : default_target
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+
+# A target that is always out of date.
+cmake_force:
+
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E remove -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/tingjie/src/operating-system/API
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/tingjie/src/operating-system/API/.build
+
+#=============================================================================
+# Directory level rules for the build root directory
+
+# The main recursive "all" target.
+all: CMakeFiles/snakeoil_api.dir/all
+
+.PHONY : all
+
+# The main recursive "preinstall" target.
+preinstall:
+
+.PHONY : preinstall
+
+# The main recursive "clean" target.
+clean: CMakeFiles/snakeoil_api.dir/clean
+
+.PHONY : clean
+
+#=============================================================================
+# Target rules for target CMakeFiles/snakeoil_api.dir
+
+# All Build rule for target.
+CMakeFiles/snakeoil_api.dir/all:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/depend
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/build
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 "Built target snakeoil_api"
+.PHONY : CMakeFiles/snakeoil_api.dir/all
+
+# Build rule for subdir invocation for target.
+CMakeFiles/snakeoil_api.dir/rule: cmake_check_build_system
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/tingjie/src/operating-system/API/.build/CMakeFiles 26
+	$(MAKE) -f CMakeFiles/Makefile2 CMakeFiles/snakeoil_api.dir/all
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/tingjie/src/operating-system/API/.build/CMakeFiles 0
+.PHONY : CMakeFiles/snakeoil_api.dir/rule
+
+# Convenience name for target.
+snakeoil_api: CMakeFiles/snakeoil_api.dir/rule
+
+.PHONY : snakeoil_api
+
+# clean rule for target.
+CMakeFiles/snakeoil_api.dir/clean:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/clean
+.PHONY : CMakeFiles/snakeoil_api.dir/clean
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+
diff --git a/API/.build/CMakeFiles/TargetDirectories.txt b/API/.build/CMakeFiles/TargetDirectories.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8a6602bb878da11a932225c3b13ec82c34a2e017
--- /dev/null
+++ b/API/.build/CMakeFiles/TargetDirectories.txt
@@ -0,0 +1,3 @@
+/home/tingjie/src/operating-system/API/.build/CMakeFiles/rebuild_cache.dir
+/home/tingjie/src/operating-system/API/.build/CMakeFiles/edit_cache.dir
+/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir
diff --git a/API/.build/CMakeFiles/cmake.check_cache b/API/.build/CMakeFiles/cmake.check_cache
new file mode 100644
index 0000000000000000000000000000000000000000..3dccd731726d7faa8b29d8d7dba3b981a53ca497
--- /dev/null
+++ b/API/.build/CMakeFiles/cmake.check_cache
@@ -0,0 +1 @@
+# This file is generated by cmake for dependency checking of the CMakeCache.txt file
diff --git a/API/.build/CMakeFiles/progress.marks b/API/.build/CMakeFiles/progress.marks
new file mode 100644
index 0000000000000000000000000000000000000000..6f4247a6255c99f420d1df558d68745592862ff7
--- /dev/null
+++ b/API/.build/CMakeFiles/progress.marks
@@ -0,0 +1 @@
+26
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/CXX.includecache b/API/.build/CMakeFiles/snakeoil_api.dir/CXX.includecache
new file mode 100644
index 0000000000000000000000000000000000000000..6b6c32088bf4c301eea1b74b59313ee43590b78d
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/CXX.includecache
@@ -0,0 +1,566 @@
+#IncludeRegexLine: ^[ 	]*[#%][ 	]*(include|import)[ 	]*[<"]([^">]+)([">])
+
+#IncludeRegexScan: ^.*$
+
+#IncludeRegexComplain: ^$
+
+#IncludeRegexTransform: 
+
+../inc/BackEnd.hpp
+Config.hpp
+../inc/Config.hpp
+Json.hpp
+../inc/Json.hpp
+statistics.hpp
+../inc/statistics.hpp
+map
+-
+
+../inc/Config.hpp
+sqlite3.h
+-
+stdafx.hpp
+../inc/stdafx.hpp
+string
+-
+vector
+-
+
+../inc/Json.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+vector
+-
+
+../inc/Quotes.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+string
+-
+
+../inc/Remote.hpp
+RemoteInterface.hpp
+../inc/RemoteInterface.hpp
+
+../inc/RemoteInterface.hpp
+strings.hpp
+../inc/strings.hpp
+vector
+-
+
+../inc/RemoteLMS.hpp
+RemoteInterface.hpp
+../inc/RemoteInterface.hpp
+
+../inc/RestWrapper.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+
+../inc/audio.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+strings.hpp
+../inc/strings.hpp
+
+../inc/browse.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+
+../inc/dashboard.hpp
+strings.hpp
+../inc/strings.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+
+../inc/features.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+
+../inc/library.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+utils.hpp
+../inc/utils.hpp
+
+../inc/network.hpp
+utils.hpp
+../inc/utils.hpp
+
+../inc/os.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+pplx/pplxlinux.h
+-
+
+../inc/players.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+
+../inc/snakeoil.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+string
+-
+
+../inc/snakesys.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+Json.hpp
+../inc/Json.hpp
+string
+-
+
+../inc/statistics.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+deque
+-
+
+../inc/stdafx.hpp
+stdlib.h
+-
+string
+-
+vector
+-
+algorithm
+-
+sstream
+-
+iostream
+-
+fstream
+-
+random
+-
+Windows.h
+-
+sys/time.h
+-
+cpprest/json.h
+../inc/cpprest/json.h
+cpprest/http_listener.h
+../inc/cpprest/http_listener.h
+cpprest/uri.h
+../inc/cpprest/uri.h
+cpprest/asyncrt_utils.h
+../inc/cpprest/asyncrt_utils.h
+
+../inc/strings.hpp
+string
+-
+vector
+-
+
+../inc/task.hpp
+string
+-
+sstream
+-
+
+../inc/time.hpp
+time.h
+-
+string
+-
+
+../inc/utils.hpp
+strings.hpp
+../inc/strings.hpp
+
+../inc/version.hpp
+stdafx.hpp
+../inc/stdafx.hpp
+vector
+-
+string
+-
+
+/home/tingjie/src/operating-system/API/src/BackEnd.cpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+dashboard.hpp
+/home/tingjie/src/operating-system/API/src/dashboard.hpp
+network.hpp
+/home/tingjie/src/operating-system/API/src/network.hpp
+library.hpp
+/home/tingjie/src/operating-system/API/src/library.hpp
+audio.hpp
+/home/tingjie/src/operating-system/API/src/audio.hpp
+players.hpp
+/home/tingjie/src/operating-system/API/src/players.hpp
+snakeoil.hpp
+/home/tingjie/src/operating-system/API/src/snakeoil.hpp
+snakesys.hpp
+/home/tingjie/src/operating-system/API/src/snakesys.hpp
+version.hpp
+/home/tingjie/src/operating-system/API/src/version.hpp
+browse.hpp
+/home/tingjie/src/operating-system/API/src/browse.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+time.hpp
+/home/tingjie/src/operating-system/API/src/time.hpp
+task.hpp
+/home/tingjie/src/operating-system/API/src/task.hpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+string
+-
+algorithm
+-
+
+/home/tingjie/src/operating-system/API/src/Config.cpp
+Config.hpp
+/home/tingjie/src/operating-system/API/src/Config.hpp
+stdafx.hpp
+/home/tingjie/src/operating-system/API/src/stdafx.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+snakeoil.hpp
+/home/tingjie/src/operating-system/API/src/snakeoil.hpp
+players.hpp
+/home/tingjie/src/operating-system/API/src/players.hpp
+audio.hpp
+/home/tingjie/src/operating-system/API/src/audio.hpp
+snakeoil/activate.h
+-
+stdexcept
+-
+sstream
+-
+assert.h
+-
+
+/home/tingjie/src/operating-system/API/src/Json.cpp
+Json.hpp
+/home/tingjie/src/operating-system/API/src/Json.hpp
+
+/home/tingjie/src/operating-system/API/src/Quotes.cpp
+Quotes.hpp
+/home/tingjie/src/operating-system/API/src/Quotes.hpp
+
+/home/tingjie/src/operating-system/API/src/Remote.cpp
+Remote.hpp
+/home/tingjie/src/operating-system/API/src/Remote.hpp
+RemoteLMS.hpp
+/home/tingjie/src/operating-system/API/src/RemoteLMS.hpp
+
+/home/tingjie/src/operating-system/API/src/RemoteInterface.cpp
+RemoteInterface.hpp
+/home/tingjie/src/operating-system/API/src/RemoteInterface.hpp
+
+/home/tingjie/src/operating-system/API/src/RemoteLMS.cpp
+RemoteLMS.hpp
+/home/tingjie/src/operating-system/API/src/RemoteLMS.hpp
+
+/home/tingjie/src/operating-system/API/src/RestWrapper.cpp
+stdafx.hpp
+/home/tingjie/src/operating-system/API/src/stdafx.hpp
+RestWrapper.hpp
+/home/tingjie/src/operating-system/API/src/RestWrapper.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+cpprest/containerstream.h
+-
+
+/home/tingjie/src/operating-system/API/src/audio.cpp
+audio.hpp
+/home/tingjie/src/operating-system/API/src/audio.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+Json.hpp
+/home/tingjie/src/operating-system/API/src/Json.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+iostream
+-
+stdexcept
+-
+
+/home/tingjie/src/operating-system/API/src/browse.cpp
+browse.hpp
+/home/tingjie/src/operating-system/API/src/browse.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+fstream
+-
+algorithm
+-
+exception
+-
+experimental/filesystem
+-
+
+/home/tingjie/src/operating-system/API/src/dashboard.cpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+network.hpp
+/home/tingjie/src/operating-system/API/src/network.hpp
+version.hpp
+/home/tingjie/src/operating-system/API/src/version.hpp
+snakesys.hpp
+/home/tingjie/src/operating-system/API/src/snakesys.hpp
+Quotes.hpp
+/home/tingjie/src/operating-system/API/src/Quotes.hpp
+ostream
+-
+iostream
+-
+iterator
+-
+
+/home/tingjie/src/operating-system/API/src/features.cpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+Json.hpp
+/home/tingjie/src/operating-system/API/src/Json.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+
+/home/tingjie/src/operating-system/API/src/library.cpp
+library.hpp
+/home/tingjie/src/operating-system/API/src/library.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+Json.hpp
+/home/tingjie/src/operating-system/API/src/Json.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+sstream
+-
+set
+-
+iterator
+-
+iomanip
+-
+
+/home/tingjie/src/operating-system/API/src/main.cpp
+stdafx.hpp
+/home/tingjie/src/operating-system/API/src/stdafx.hpp
+version.hpp
+/home/tingjie/src/operating-system/API/src/version.hpp
+RestWrapper.hpp
+/home/tingjie/src/operating-system/API/src/RestWrapper.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+snakesys.hpp
+/home/tingjie/src/operating-system/API/src/snakesys.hpp
+stdexcept
+-
+string
+-
+signal.h
+-
+stdio.h
+-
+iomanip
+-
+curl/curl.h
+-
+
+/home/tingjie/src/operating-system/API/src/network.cpp
+network.hpp
+/home/tingjie/src/operating-system/API/src/network.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+stdafx.hpp
+/home/tingjie/src/operating-system/API/src/stdafx.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+fstream
+-
+string.h
+-
+iostream
+-
+map
+-
+algorithm
+-
+
+/home/tingjie/src/operating-system/API/src/os.cpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+snakeoil.hpp
+/home/tingjie/src/operating-system/API/src/snakeoil.hpp
+task.hpp
+/home/tingjie/src/operating-system/API/src/task.hpp
+mcrypt.h
+-
+dirent.h
+-
+sys/types.h
+-
+stdlib.h
+-
+
+/home/tingjie/src/operating-system/API/src/players.cpp
+players.hpp
+/home/tingjie/src/operating-system/API/src/players.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+snakeoil.hpp
+/home/tingjie/src/operating-system/API/src/snakeoil.hpp
+audio.hpp
+/home/tingjie/src/operating-system/API/src/audio.hpp
+task.hpp
+/home/tingjie/src/operating-system/API/src/task.hpp
+time.hpp
+/home/tingjie/src/operating-system/API/src/time.hpp
+dirent.h
+-
+iostream
+-
+
+/home/tingjie/src/operating-system/API/src/snakeoil.cpp
+snakeoil.hpp
+/home/tingjie/src/operating-system/API/src/snakeoil.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+task.hpp
+/home/tingjie/src/operating-system/API/src/task.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+audio.hpp
+/home/tingjie/src/operating-system/API/src/audio.hpp
+players.hpp
+/home/tingjie/src/operating-system/API/src/players.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+snakeoil/activate.h
+-
+unistd.h
+-
+algorithm
+-
+sstream
+-
+chrono
+-
+iomanip
+-
+
+/home/tingjie/src/operating-system/API/src/snakesys.cpp
+snakesys.hpp
+/home/tingjie/src/operating-system/API/src/snakesys.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+players.hpp
+/home/tingjie/src/operating-system/API/src/players.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+task.hpp
+/home/tingjie/src/operating-system/API/src/task.hpp
+time.hpp
+/home/tingjie/src/operating-system/API/src/time.hpp
+dirent.h
+-
+iomanip
+-
+algorithm
+-
+fstream
+-
+memory
+-
+sys/types.h
+-
+sys/stat.h
+-
+b64/decode.h
+-
+
+/home/tingjie/src/operating-system/API/src/statistics.cpp
+statistics.hpp
+/home/tingjie/src/operating-system/API/src/statistics.hpp
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+
+/home/tingjie/src/operating-system/API/src/stdafx.cpp
+stdafx.hpp
+/home/tingjie/src/operating-system/API/src/stdafx.hpp
+
+/home/tingjie/src/operating-system/API/src/task.cpp
+task.hpp
+/home/tingjie/src/operating-system/API/src/task.hpp
+
+/home/tingjie/src/operating-system/API/src/time.cpp
+time.hpp
+/home/tingjie/src/operating-system/API/src/time.hpp
+stdexcept
+-
+iostream
+-
+
+/home/tingjie/src/operating-system/API/src/utils.cpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+dirent.h
+-
+stdio.h
+-
+sys/types.h
+-
+sys/stat.h
+-
+pwd.h
+-
+grp.h
+-
+algorithm
+-
+iostream
+-
+iomanip
+-
+sstream
+-
+fstream
+-
+set
+-
+os.hpp
+/home/tingjie/src/operating-system/API/src/os.hpp
+
+/home/tingjie/src/operating-system/API/src/version.cpp
+version.hpp
+/home/tingjie/src/operating-system/API/src/version.hpp
+utils.hpp
+/home/tingjie/src/operating-system/API/src/utils.hpp
+BackEnd.hpp
+/home/tingjie/src/operating-system/API/src/BackEnd.hpp
+features.hpp
+/home/tingjie/src/operating-system/API/src/features.hpp
+
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/DependInfo.cmake b/API/.build/CMakeFiles/snakeoil_api.dir/DependInfo.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..32321812f0bcbcc733ba13adc3e1f356d661d39a
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/DependInfo.cmake
@@ -0,0 +1,46 @@
+# The set of languages for which implicit dependencies are needed:
+set(CMAKE_DEPENDS_LANGUAGES
+  "CXX"
+  )
+# The set of files for implicit dependencies of each language:
+set(CMAKE_DEPENDS_CHECK_CXX
+  "/home/tingjie/src/operating-system/API/src/BackEnd.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/Config.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/Config.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/Json.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/Json.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/Quotes.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/Remote.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/RemoteInterface.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/RemoteLMS.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/RestWrapper.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/audio.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/audio.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/browse.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/browse.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/dashboard.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/features.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/features.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/library.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/library.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/main.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/main.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/network.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/network.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/os.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/os.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/players.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/players.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/snakeoil.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/snakesys.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/statistics.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/stdafx.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/task.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/task.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/time.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/time.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/utils.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/utils.cpp.o"
+  "/home/tingjie/src/operating-system/API/src/version.cpp" "/home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/src/version.cpp.o"
+  )
+set(CMAKE_CXX_COMPILER_ID "GNU")
+
+# The include file search paths:
+set(CMAKE_CXX_TARGET_INCLUDE_PATH
+  "."
+  "../inc"
+  )
+
+# Targets to which this target links.
+set(CMAKE_TARGET_LINKED_INFO_FILES
+  )
+
+# Fortran module output directory.
+set(CMAKE_Fortran_TARGET_MODULE_DIR "")
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/build.make b/API/.build/CMakeFiles/snakeoil_api.dir/build.make
new file mode 100644
index 0000000000000000000000000000000000000000..e516599bffe88164eba48b22d91977762e51046e
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/build.make
@@ -0,0 +1,458 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# Delete rule output on recipe failure.
+.DELETE_ON_ERROR:
+
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+
+# A target that is always out of date.
+cmake_force:
+
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E remove -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/tingjie/src/operating-system/API
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/tingjie/src/operating-system/API/.build
+
+# Include any dependencies generated for this target.
+include CMakeFiles/snakeoil_api.dir/depend.make
+
+# Include the progress variables for this target.
+include CMakeFiles/snakeoil_api.dir/progress.make
+
+# Include the compile flags for this target's objects.
+include CMakeFiles/snakeoil_api.dir/flags.make
+
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../src/audio.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object CMakeFiles/snakeoil_api.dir/src/audio.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/audio.cpp.o -c /home/tingjie/src/operating-system/API/src/audio.cpp
+
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/audio.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/audio.cpp > CMakeFiles/snakeoil_api.dir/src/audio.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/audio.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/audio.cpp -o CMakeFiles/snakeoil_api.dir/src/audio.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../src/features.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Building CXX object CMakeFiles/snakeoil_api.dir/src/features.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/features.cpp.o -c /home/tingjie/src/operating-system/API/src/features.cpp
+
+CMakeFiles/snakeoil_api.dir/src/features.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/features.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/features.cpp > CMakeFiles/snakeoil_api.dir/src/features.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/features.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/features.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/features.cpp -o CMakeFiles/snakeoil_api.dir/src/features.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../src/os.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Building CXX object CMakeFiles/snakeoil_api.dir/src/os.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/os.cpp.o -c /home/tingjie/src/operating-system/API/src/os.cpp
+
+CMakeFiles/snakeoil_api.dir/src/os.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/os.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/os.cpp > CMakeFiles/snakeoil_api.dir/src/os.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/os.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/os.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/os.cpp -o CMakeFiles/snakeoil_api.dir/src/os.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o: ../src/RemoteLMS.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Building CXX object CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o -c /home/tingjie/src/operating-system/API/src/RemoteLMS.cpp
+
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/RemoteLMS.cpp > CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/RemoteLMS.cpp -o CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o: ../src/stdafx.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Building CXX object CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o -c /home/tingjie/src/operating-system/API/src/stdafx.cpp
+
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/stdafx.cpp > CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/stdafx.cpp -o CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/time.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/time.cpp.o: ../src/time.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Building CXX object CMakeFiles/snakeoil_api.dir/src/time.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/time.cpp.o -c /home/tingjie/src/operating-system/API/src/time.cpp
+
+CMakeFiles/snakeoil_api.dir/src/time.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/time.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/time.cpp > CMakeFiles/snakeoil_api.dir/src/time.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/time.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/time.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/time.cpp -o CMakeFiles/snakeoil_api.dir/src/time.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../src/Config.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_7) "Building CXX object CMakeFiles/snakeoil_api.dir/src/Config.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/Config.cpp.o -c /home/tingjie/src/operating-system/API/src/Config.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/Config.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/Config.cpp > CMakeFiles/snakeoil_api.dir/src/Config.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/Config.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/Config.cpp -o CMakeFiles/snakeoil_api.dir/src/Config.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../src/main.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_8) "Building CXX object CMakeFiles/snakeoil_api.dir/src/main.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/main.cpp.o -c /home/tingjie/src/operating-system/API/src/main.cpp
+
+CMakeFiles/snakeoil_api.dir/src/main.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/main.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/main.cpp > CMakeFiles/snakeoil_api.dir/src/main.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/main.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/main.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/main.cpp -o CMakeFiles/snakeoil_api.dir/src/main.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: ../src/Remote.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_9) "Building CXX object CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o -c /home/tingjie/src/operating-system/API/src/Remote.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/Remote.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/Remote.cpp > CMakeFiles/snakeoil_api.dir/src/Remote.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/Remote.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/Remote.cpp -o CMakeFiles/snakeoil_api.dir/src/Remote.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../src/snakesys.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_10) "Building CXX object CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o -c /home/tingjie/src/operating-system/API/src/snakesys.cpp
+
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/snakesys.cpp > CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/snakesys.cpp -o CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../src/BackEnd.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_11) "Building CXX object CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o -c /home/tingjie/src/operating-system/API/src/BackEnd.cpp
+
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/BackEnd.cpp > CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/BackEnd.cpp -o CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.o: ../src/Json.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_12) "Building CXX object CMakeFiles/snakeoil_api.dir/src/Json.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/Json.cpp.o -c /home/tingjie/src/operating-system/API/src/Json.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/Json.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/Json.cpp > CMakeFiles/snakeoil_api.dir/src/Json.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/Json.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/Json.cpp -o CMakeFiles/snakeoil_api.dir/src/Json.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../src/players.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_13) "Building CXX object CMakeFiles/snakeoil_api.dir/src/players.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/players.cpp.o -c /home/tingjie/src/operating-system/API/src/players.cpp
+
+CMakeFiles/snakeoil_api.dir/src/players.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/players.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/players.cpp > CMakeFiles/snakeoil_api.dir/src/players.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/players.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/players.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/players.cpp -o CMakeFiles/snakeoil_api.dir/src/players.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../src/RestWrapper.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_14) "Building CXX object CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o -c /home/tingjie/src/operating-system/API/src/RestWrapper.cpp
+
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/RestWrapper.cpp > CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/RestWrapper.cpp -o CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: ../src/utils.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_15) "Building CXX object CMakeFiles/snakeoil_api.dir/src/utils.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/utils.cpp.o -c /home/tingjie/src/operating-system/API/src/utils.cpp
+
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/utils.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/utils.cpp > CMakeFiles/snakeoil_api.dir/src/utils.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/utils.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/utils.cpp -o CMakeFiles/snakeoil_api.dir/src/utils.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../src/dashboard.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_16) "Building CXX object CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o -c /home/tingjie/src/operating-system/API/src/dashboard.cpp
+
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/dashboard.cpp > CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/dashboard.cpp -o CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../src/network.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_17) "Building CXX object CMakeFiles/snakeoil_api.dir/src/network.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/network.cpp.o -c /home/tingjie/src/operating-system/API/src/network.cpp
+
+CMakeFiles/snakeoil_api.dir/src/network.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/network.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/network.cpp > CMakeFiles/snakeoil_api.dir/src/network.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/network.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/network.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/network.cpp -o CMakeFiles/snakeoil_api.dir/src/network.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o: ../src/RemoteInterface.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_18) "Building CXX object CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o -c /home/tingjie/src/operating-system/API/src/RemoteInterface.cpp
+
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/RemoteInterface.cpp > CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/RemoteInterface.cpp -o CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o: ../src/statistics.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_19) "Building CXX object CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o -c /home/tingjie/src/operating-system/API/src/statistics.cpp
+
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/statistics.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/statistics.cpp > CMakeFiles/snakeoil_api.dir/src/statistics.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/statistics.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/statistics.cpp -o CMakeFiles/snakeoil_api.dir/src/statistics.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/task.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/task.cpp.o: ../src/task.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_20) "Building CXX object CMakeFiles/snakeoil_api.dir/src/task.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/task.cpp.o -c /home/tingjie/src/operating-system/API/src/task.cpp
+
+CMakeFiles/snakeoil_api.dir/src/task.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/task.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/task.cpp > CMakeFiles/snakeoil_api.dir/src/task.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/task.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/task.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/task.cpp -o CMakeFiles/snakeoil_api.dir/src/task.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o: ../src/browse.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_21) "Building CXX object CMakeFiles/snakeoil_api.dir/src/browse.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/browse.cpp.o -c /home/tingjie/src/operating-system/API/src/browse.cpp
+
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/browse.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/browse.cpp > CMakeFiles/snakeoil_api.dir/src/browse.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/browse.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/browse.cpp -o CMakeFiles/snakeoil_api.dir/src/browse.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../src/library.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_22) "Building CXX object CMakeFiles/snakeoil_api.dir/src/library.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/library.cpp.o -c /home/tingjie/src/operating-system/API/src/library.cpp
+
+CMakeFiles/snakeoil_api.dir/src/library.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/library.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/library.cpp > CMakeFiles/snakeoil_api.dir/src/library.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/library.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/library.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/library.cpp -o CMakeFiles/snakeoil_api.dir/src/library.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o: ../src/Quotes.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_23) "Building CXX object CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o -c /home/tingjie/src/operating-system/API/src/Quotes.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/Quotes.cpp > CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/Quotes.cpp -o CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../src/snakeoil.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_24) "Building CXX object CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o -c /home/tingjie/src/operating-system/API/src/snakeoil.cpp
+
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/snakeoil.cpp > CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/snakeoil.cpp -o CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.s
+
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: CMakeFiles/snakeoil_api.dir/flags.make
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../src/version.cpp
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_25) "Building CXX object CMakeFiles/snakeoil_api.dir/src/version.cpp.o"
+	/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/snakeoil_api.dir/src/version.cpp.o -c /home/tingjie/src/operating-system/API/src/version.cpp
+
+CMakeFiles/snakeoil_api.dir/src/version.cpp.i: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/snakeoil_api.dir/src/version.cpp.i"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/tingjie/src/operating-system/API/src/version.cpp > CMakeFiles/snakeoil_api.dir/src/version.cpp.i
+
+CMakeFiles/snakeoil_api.dir/src/version.cpp.s: cmake_force
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/snakeoil_api.dir/src/version.cpp.s"
+	/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/tingjie/src/operating-system/API/src/version.cpp -o CMakeFiles/snakeoil_api.dir/src/version.cpp.s
+
+# Object files for target snakeoil_api
+snakeoil_api_OBJECTS = \
+"CMakeFiles/snakeoil_api.dir/src/audio.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/features.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/os.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/time.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/Config.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/main.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/Json.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/players.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/utils.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/network.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/task.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/browse.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/library.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o" \
+"CMakeFiles/snakeoil_api.dir/src/version.cpp.o"
+
+# External object files for target snakeoil_api
+snakeoil_api_EXTERNAL_OBJECTS =
+
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/audio.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/features.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/os.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/time.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/Config.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/main.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/Json.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/players.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/utils.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/network.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/task.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/browse.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/library.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/src/version.cpp.o
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/build.make
+snakeoil-rest: CMakeFiles/snakeoil_api.dir/link.txt
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/home/tingjie/src/operating-system/API/.build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_26) "Linking CXX executable snakeoil-rest"
+	$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/snakeoil_api.dir/link.txt --verbose=$(VERBOSE)
+
+# Rule to build all files generated by this target.
+CMakeFiles/snakeoil_api.dir/build: snakeoil-rest
+
+.PHONY : CMakeFiles/snakeoil_api.dir/build
+
+CMakeFiles/snakeoil_api.dir/clean:
+	$(CMAKE_COMMAND) -P CMakeFiles/snakeoil_api.dir/cmake_clean.cmake
+.PHONY : CMakeFiles/snakeoil_api.dir/clean
+
+CMakeFiles/snakeoil_api.dir/depend:
+	cd /home/tingjie/src/operating-system/API/.build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/tingjie/src/operating-system/API /home/tingjie/src/operating-system/API /home/tingjie/src/operating-system/API/.build /home/tingjie/src/operating-system/API/.build /home/tingjie/src/operating-system/API/.build/CMakeFiles/snakeoil_api.dir/DependInfo.cmake --color=$(COLOR)
+.PHONY : CMakeFiles/snakeoil_api.dir/depend
+
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/cmake_clean.cmake b/API/.build/CMakeFiles/snakeoil_api.dir/cmake_clean.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..495d964c071965aa861f21bc34351190c16e2331
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/cmake_clean.cmake
@@ -0,0 +1,34 @@
+file(REMOVE_RECURSE
+  "CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/Config.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/Json.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/audio.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/browse.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/features.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/library.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/main.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/network.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/os.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/players.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/task.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/time.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/utils.cpp.o"
+  "CMakeFiles/snakeoil_api.dir/src/version.cpp.o"
+  "snakeoil-rest"
+  "snakeoil-rest.pdb"
+)
+
+# Per-language clean rules from dependency scanning.
+foreach(lang CXX)
+  include(CMakeFiles/snakeoil_api.dir/cmake_clean_${lang}.cmake OPTIONAL)
+endforeach()
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/depend.internal b/API/.build/CMakeFiles/snakeoil_api.dir/depend.internal
new file mode 100644
index 0000000000000000000000000000000000000000..fce537a4d29fa87aed714e124de08ab7a8887fb1
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/depend.internal
@@ -0,0 +1,228 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/audio.hpp
+ ../inc/browse.hpp
+ ../inc/dashboard.hpp
+ ../inc/features.hpp
+ ../inc/library.hpp
+ ../inc/network.hpp
+ ../inc/os.hpp
+ ../inc/players.hpp
+ ../inc/snakeoil.hpp
+ ../inc/snakesys.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/task.hpp
+ ../inc/time.hpp
+ ../inc/utils.hpp
+ ../inc/version.hpp
+ /home/tingjie/src/operating-system/API/src/BackEnd.cpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o
+ ../inc/Config.hpp
+ ../inc/audio.hpp
+ ../inc/os.hpp
+ ../inc/players.hpp
+ ../inc/snakeoil.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/Config.cpp
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.o
+ ../inc/Json.hpp
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/Json.cpp
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o
+ ../inc/Quotes.hpp
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/Quotes.cpp
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o
+ ../inc/Remote.hpp
+ ../inc/RemoteInterface.hpp
+ ../inc/RemoteLMS.hpp
+ ../inc/strings.hpp
+ /home/tingjie/src/operating-system/API/src/Remote.cpp
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o
+ ../inc/RemoteInterface.hpp
+ ../inc/strings.hpp
+ /home/tingjie/src/operating-system/API/src/RemoteInterface.cpp
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o
+ ../inc/RemoteInterface.hpp
+ ../inc/RemoteLMS.hpp
+ ../inc/strings.hpp
+ /home/tingjie/src/operating-system/API/src/RemoteLMS.cpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/RestWrapper.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/RestWrapper.cpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/audio.hpp
+ ../inc/features.hpp
+ ../inc/os.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/audio.cpp
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o
+ ../inc/browse.hpp
+ ../inc/os.hpp
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/browse.cpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/Quotes.hpp
+ ../inc/network.hpp
+ ../inc/os.hpp
+ ../inc/snakesys.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ ../inc/version.hpp
+ /home/tingjie/src/operating-system/API/src/dashboard.cpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/features.hpp
+ ../inc/os.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/features.cpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/features.hpp
+ ../inc/library.hpp
+ ../inc/os.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/library.cpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/RestWrapper.hpp
+ ../inc/os.hpp
+ ../inc/snakesys.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/version.hpp
+ /home/tingjie/src/operating-system/API/src/main.cpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/network.hpp
+ ../inc/os.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/network.cpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/os.hpp
+ ../inc/snakeoil.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/task.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/os.cpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/audio.hpp
+ ../inc/features.hpp
+ ../inc/os.hpp
+ ../inc/players.hpp
+ ../inc/snakeoil.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/task.hpp
+ ../inc/time.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/players.cpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/audio.hpp
+ ../inc/features.hpp
+ ../inc/os.hpp
+ ../inc/players.hpp
+ ../inc/snakeoil.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/task.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/snakeoil.cpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/os.hpp
+ ../inc/players.hpp
+ ../inc/snakesys.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/task.hpp
+ ../inc/time.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/snakesys.cpp
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o
+ ../inc/os.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/statistics.cpp
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o
+ ../inc/stdafx.hpp
+ /home/tingjie/src/operating-system/API/src/stdafx.cpp
+CMakeFiles/snakeoil_api.dir/src/task.cpp.o
+ ../inc/task.hpp
+ /home/tingjie/src/operating-system/API/src/task.cpp
+CMakeFiles/snakeoil_api.dir/src/time.cpp.o
+ ../inc/time.hpp
+ /home/tingjie/src/operating-system/API/src/time.cpp
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o
+ ../inc/os.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ /home/tingjie/src/operating-system/API/src/utils.cpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o
+ ../inc/BackEnd.hpp
+ ../inc/Config.hpp
+ ../inc/Json.hpp
+ ../inc/features.hpp
+ ../inc/statistics.hpp
+ ../inc/stdafx.hpp
+ ../inc/strings.hpp
+ ../inc/utils.hpp
+ ../inc/version.hpp
+ /home/tingjie/src/operating-system/API/src/version.cpp
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/depend.make b/API/.build/CMakeFiles/snakeoil_api.dir/depend.make
new file mode 100644
index 0000000000000000000000000000000000000000..18c07ec587a4b49c99ca29d3a5f556733cc57a95
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/depend.make
@@ -0,0 +1,228 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/audio.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/browse.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/dashboard.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/library.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/network.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/players.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/snakeoil.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/snakesys.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/task.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/time.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../inc/version.hpp
+CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o: ../src/BackEnd.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/audio.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/players.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/snakeoil.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/Config.cpp.o: ../src/Config.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/Json.cpp.o: ../src/Json.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o: ../inc/Quotes.hpp
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o: ../src/Quotes.cpp
+
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: ../inc/Remote.hpp
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: ../inc/RemoteInterface.hpp
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: ../inc/RemoteLMS.hpp
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o: ../src/Remote.cpp
+
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o: ../inc/RemoteInterface.hpp
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o: ../src/RemoteInterface.cpp
+
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o: ../inc/RemoteInterface.hpp
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o: ../inc/RemoteLMS.hpp
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o: ../src/RemoteLMS.cpp
+
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../inc/RestWrapper.hpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o: ../src/RestWrapper.cpp
+
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/audio.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/audio.cpp.o: ../src/audio.cpp
+
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o: ../inc/browse.hpp
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/browse.cpp.o: ../src/browse.cpp
+
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/Quotes.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/network.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/snakesys.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../inc/version.hpp
+CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o: ../src/dashboard.cpp
+
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/features.cpp.o: ../src/features.cpp
+
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/library.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/library.cpp.o: ../src/library.cpp
+
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/RestWrapper.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/snakesys.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../inc/version.hpp
+CMakeFiles/snakeoil_api.dir/src/main.cpp.o: ../src/main.cpp
+
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/network.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/network.cpp.o: ../src/network.cpp
+
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/snakeoil.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/task.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/os.cpp.o: ../src/os.cpp
+
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/audio.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/players.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/snakeoil.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/task.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/time.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/players.cpp.o: ../src/players.cpp
+
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/audio.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/players.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/snakeoil.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/task.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o: ../src/snakeoil.cpp
+
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/players.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/snakesys.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/task.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/time.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o: ../src/snakesys.cpp
+
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o: ../src/statistics.cpp
+
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o: ../src/stdafx.cpp
+
+CMakeFiles/snakeoil_api.dir/src/task.cpp.o: ../inc/task.hpp
+CMakeFiles/snakeoil_api.dir/src/task.cpp.o: ../src/task.cpp
+
+CMakeFiles/snakeoil_api.dir/src/time.cpp.o: ../inc/time.hpp
+CMakeFiles/snakeoil_api.dir/src/time.cpp.o: ../src/time.cpp
+
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: ../inc/os.hpp
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/utils.cpp.o: ../src/utils.cpp
+
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/BackEnd.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/Config.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/Json.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/features.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/statistics.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/stdafx.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/strings.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/utils.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../inc/version.hpp
+CMakeFiles/snakeoil_api.dir/src/version.cpp.o: ../src/version.cpp
+
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/flags.make b/API/.build/CMakeFiles/snakeoil_api.dir/flags.make
new file mode 100644
index 0000000000000000000000000000000000000000..2a01f00dff2f5ef3f6c5f87e149f200fdaa3c870
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/flags.make
@@ -0,0 +1,10 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# compile CXX with /usr/bin/c++
+CXX_FLAGS =   -std=gnu++17
+
+CXX_DEFINES = 
+
+CXX_INCLUDES = -I/home/tingjie/src/operating-system/API/.build -I/home/tingjie/src/operating-system/API/inc 
+
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/link.txt b/API/.build/CMakeFiles/snakeoil_api.dir/link.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87b03011cc10b9ff3986ecc783029b53169ff5ab
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/link.txt
@@ -0,0 +1 @@
+/usr/bin/c++    -static CMakeFiles/snakeoil_api.dir/src/audio.cpp.o CMakeFiles/snakeoil_api.dir/src/features.cpp.o CMakeFiles/snakeoil_api.dir/src/os.cpp.o CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o CMakeFiles/snakeoil_api.dir/src/time.cpp.o CMakeFiles/snakeoil_api.dir/src/Config.cpp.o CMakeFiles/snakeoil_api.dir/src/main.cpp.o CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o CMakeFiles/snakeoil_api.dir/src/Json.cpp.o CMakeFiles/snakeoil_api.dir/src/players.cpp.o CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o CMakeFiles/snakeoil_api.dir/src/utils.cpp.o CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o CMakeFiles/snakeoil_api.dir/src/network.cpp.o CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o CMakeFiles/snakeoil_api.dir/src/task.cpp.o CMakeFiles/snakeoil_api.dir/src/browse.cpp.o CMakeFiles/snakeoil_api.dir/src/library.cpp.o CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o CMakeFiles/snakeoil_api.dir/src/version.cpp.o  -o snakeoil-rest  -lsqlite3 -lmcrypt -lcpprest -lcurl -lb64 -lssl -lcrypto -lboost_system -ldl -lidn2 -lunistring -lstdc++ -lpthread -lm -lstdc++fs -lz -lsnakeoil_activate 
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/progress.make b/API/.build/CMakeFiles/snakeoil_api.dir/progress.make
new file mode 100644
index 0000000000000000000000000000000000000000..4334314440a2d03ba69b07cbdc3b131d08f3e98b
--- /dev/null
+++ b/API/.build/CMakeFiles/snakeoil_api.dir/progress.make
@@ -0,0 +1,27 @@
+CMAKE_PROGRESS_1 = 1
+CMAKE_PROGRESS_2 = 2
+CMAKE_PROGRESS_3 = 3
+CMAKE_PROGRESS_4 = 4
+CMAKE_PROGRESS_5 = 5
+CMAKE_PROGRESS_6 = 6
+CMAKE_PROGRESS_7 = 7
+CMAKE_PROGRESS_8 = 8
+CMAKE_PROGRESS_9 = 9
+CMAKE_PROGRESS_10 = 10
+CMAKE_PROGRESS_11 = 11
+CMAKE_PROGRESS_12 = 12
+CMAKE_PROGRESS_13 = 13
+CMAKE_PROGRESS_14 = 14
+CMAKE_PROGRESS_15 = 15
+CMAKE_PROGRESS_16 = 16
+CMAKE_PROGRESS_17 = 17
+CMAKE_PROGRESS_18 = 18
+CMAKE_PROGRESS_19 = 19
+CMAKE_PROGRESS_20 = 20
+CMAKE_PROGRESS_21 = 21
+CMAKE_PROGRESS_22 = 22
+CMAKE_PROGRESS_23 = 23
+CMAKE_PROGRESS_24 = 24
+CMAKE_PROGRESS_25 = 25
+CMAKE_PROGRESS_26 = 26
+
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..330830bf77ef785433dc55eb68de681272fe0165
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/Config.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/Config.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..b8acc8409bb47fa2f47ccc15377210f72bcfccf2
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/Config.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/Json.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/Json.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..df466ecc6f34dbc444fc5dbae767252478fdbe3d
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/Json.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..62d32381ca04f49cc0c3a573820142ccf8fa413f
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..908f5569fd24c9ae08cc6e5ce9b66b4dc8f0269c
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..cd9f31bdd87324a05f7c1a742ef98c12686323e1
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..cc66730fe5f620cdb1c8cdd52855974bbae90418
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..1e00fb993a35ebc16378e73132a1e542ec9423c5
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/audio.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/audio.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..493282a4f56609b20215610aed9c057d8f451988
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/audio.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/browse.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/browse.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..e66bd979d36da8e6255efec65c178bdc257cf4d4
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/browse.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..c59ca0b11b22e7fa30692c5f54e3c00ecb1b8813
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/features.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/features.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..d760ee41788e88601bfdb1db2638767b2349e1bf
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/features.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/library.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/library.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..1dd4529a58fccf40b6d6c3ce9ae4251282adc99f
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/library.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/main.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/main.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..5f1892dc18b5ecc368f7223b06302d8ed778fd97
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/main.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/network.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/network.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..d8d13cbb11abf56f0ef63940b4dd2ad375fa5441
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/network.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/os.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/os.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..96f7b80384c36b5768ebc29eedf12ab1585475c6
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/os.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/players.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/players.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..afe24e77dabb1ff318472537c7ce9d23d78e838e
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/players.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..dbc0e7fb476c4975abfc3341fe89560f95aef2c9
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..1556a5386a1eb41d8e7098d01b0a0597fbe909b8
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..cbc741b0e646acbcf84292c8d68495f9a9318d43
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..e80d4454d9a0a236cc05b9e2eb888a4119d5ccf3
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/task.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/task.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..e4b7e51e9302fc5156041f418b7dd0133470f1d1
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/task.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/time.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/time.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..a466dbf23d7f10007dd5e71d25acac792e536680
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/time.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/utils.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/utils.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..067bfae2aa31ac50d686e01ff34a86a27e49202a
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/utils.cpp.o differ
diff --git a/API/.build/CMakeFiles/snakeoil_api.dir/src/version.cpp.o b/API/.build/CMakeFiles/snakeoil_api.dir/src/version.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..b78cab62d34407e4af3461193dd6e194def35799
Binary files /dev/null and b/API/.build/CMakeFiles/snakeoil_api.dir/src/version.cpp.o differ
diff --git a/API/.build/Makefile b/API/.build/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..82319e19c3bd60e7ddc4ccc209d2c015ce3302e7
--- /dev/null
+++ b/API/.build/Makefile
@@ -0,0 +1,898 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# Default target executed when no arguments are given to make.
+default_target: all
+
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+
+# A target that is always out of date.
+cmake_force:
+
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E remove -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/tingjie/src/operating-system/API
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/tingjie/src/operating-system/API/.build
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+	/usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+
+.PHONY : rebuild_cache/fast
+
+# Special rule for the target edit_cache
+edit_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
+	/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+
+.PHONY : edit_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/tingjie/src/operating-system/API/.build/CMakeFiles /home/tingjie/src/operating-system/API/.build/CMakeFiles/progress.marks
+	$(MAKE) -f CMakeFiles/Makefile2 all
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/tingjie/src/operating-system/API/.build/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+	$(MAKE) -f CMakeFiles/Makefile2 clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+	$(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+	$(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+#=============================================================================
+# Target rules for targets named snakeoil_api
+
+# Build rule for target.
+snakeoil_api: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 snakeoil_api
+.PHONY : snakeoil_api
+
+# fast build rule for target.
+snakeoil_api/fast:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/build
+.PHONY : snakeoil_api/fast
+
+src/BackEnd.o: src/BackEnd.cpp.o
+
+.PHONY : src/BackEnd.o
+
+# target to build an object file
+src/BackEnd.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.o
+.PHONY : src/BackEnd.cpp.o
+
+src/BackEnd.i: src/BackEnd.cpp.i
+
+.PHONY : src/BackEnd.i
+
+# target to preprocess a source file
+src/BackEnd.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.i
+.PHONY : src/BackEnd.cpp.i
+
+src/BackEnd.s: src/BackEnd.cpp.s
+
+.PHONY : src/BackEnd.s
+
+# target to generate assembly for a file
+src/BackEnd.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/BackEnd.cpp.s
+.PHONY : src/BackEnd.cpp.s
+
+src/Config.o: src/Config.cpp.o
+
+.PHONY : src/Config.o
+
+# target to build an object file
+src/Config.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Config.cpp.o
+.PHONY : src/Config.cpp.o
+
+src/Config.i: src/Config.cpp.i
+
+.PHONY : src/Config.i
+
+# target to preprocess a source file
+src/Config.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Config.cpp.i
+.PHONY : src/Config.cpp.i
+
+src/Config.s: src/Config.cpp.s
+
+.PHONY : src/Config.s
+
+# target to generate assembly for a file
+src/Config.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Config.cpp.s
+.PHONY : src/Config.cpp.s
+
+src/Json.o: src/Json.cpp.o
+
+.PHONY : src/Json.o
+
+# target to build an object file
+src/Json.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Json.cpp.o
+.PHONY : src/Json.cpp.o
+
+src/Json.i: src/Json.cpp.i
+
+.PHONY : src/Json.i
+
+# target to preprocess a source file
+src/Json.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Json.cpp.i
+.PHONY : src/Json.cpp.i
+
+src/Json.s: src/Json.cpp.s
+
+.PHONY : src/Json.s
+
+# target to generate assembly for a file
+src/Json.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Json.cpp.s
+.PHONY : src/Json.cpp.s
+
+src/Quotes.o: src/Quotes.cpp.o
+
+.PHONY : src/Quotes.o
+
+# target to build an object file
+src/Quotes.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.o
+.PHONY : src/Quotes.cpp.o
+
+src/Quotes.i: src/Quotes.cpp.i
+
+.PHONY : src/Quotes.i
+
+# target to preprocess a source file
+src/Quotes.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.i
+.PHONY : src/Quotes.cpp.i
+
+src/Quotes.s: src/Quotes.cpp.s
+
+.PHONY : src/Quotes.s
+
+# target to generate assembly for a file
+src/Quotes.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Quotes.cpp.s
+.PHONY : src/Quotes.cpp.s
+
+src/Remote.o: src/Remote.cpp.o
+
+.PHONY : src/Remote.o
+
+# target to build an object file
+src/Remote.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Remote.cpp.o
+.PHONY : src/Remote.cpp.o
+
+src/Remote.i: src/Remote.cpp.i
+
+.PHONY : src/Remote.i
+
+# target to preprocess a source file
+src/Remote.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Remote.cpp.i
+.PHONY : src/Remote.cpp.i
+
+src/Remote.s: src/Remote.cpp.s
+
+.PHONY : src/Remote.s
+
+# target to generate assembly for a file
+src/Remote.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/Remote.cpp.s
+.PHONY : src/Remote.cpp.s
+
+src/RemoteInterface.o: src/RemoteInterface.cpp.o
+
+.PHONY : src/RemoteInterface.o
+
+# target to build an object file
+src/RemoteInterface.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.o
+.PHONY : src/RemoteInterface.cpp.o
+
+src/RemoteInterface.i: src/RemoteInterface.cpp.i
+
+.PHONY : src/RemoteInterface.i
+
+# target to preprocess a source file
+src/RemoteInterface.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.i
+.PHONY : src/RemoteInterface.cpp.i
+
+src/RemoteInterface.s: src/RemoteInterface.cpp.s
+
+.PHONY : src/RemoteInterface.s
+
+# target to generate assembly for a file
+src/RemoteInterface.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RemoteInterface.cpp.s
+.PHONY : src/RemoteInterface.cpp.s
+
+src/RemoteLMS.o: src/RemoteLMS.cpp.o
+
+.PHONY : src/RemoteLMS.o
+
+# target to build an object file
+src/RemoteLMS.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.o
+.PHONY : src/RemoteLMS.cpp.o
+
+src/RemoteLMS.i: src/RemoteLMS.cpp.i
+
+.PHONY : src/RemoteLMS.i
+
+# target to preprocess a source file
+src/RemoteLMS.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.i
+.PHONY : src/RemoteLMS.cpp.i
+
+src/RemoteLMS.s: src/RemoteLMS.cpp.s
+
+.PHONY : src/RemoteLMS.s
+
+# target to generate assembly for a file
+src/RemoteLMS.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RemoteLMS.cpp.s
+.PHONY : src/RemoteLMS.cpp.s
+
+src/RestWrapper.o: src/RestWrapper.cpp.o
+
+.PHONY : src/RestWrapper.o
+
+# target to build an object file
+src/RestWrapper.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.o
+.PHONY : src/RestWrapper.cpp.o
+
+src/RestWrapper.i: src/RestWrapper.cpp.i
+
+.PHONY : src/RestWrapper.i
+
+# target to preprocess a source file
+src/RestWrapper.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.i
+.PHONY : src/RestWrapper.cpp.i
+
+src/RestWrapper.s: src/RestWrapper.cpp.s
+
+.PHONY : src/RestWrapper.s
+
+# target to generate assembly for a file
+src/RestWrapper.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/RestWrapper.cpp.s
+.PHONY : src/RestWrapper.cpp.s
+
+src/audio.o: src/audio.cpp.o
+
+.PHONY : src/audio.o
+
+# target to build an object file
+src/audio.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/audio.cpp.o
+.PHONY : src/audio.cpp.o
+
+src/audio.i: src/audio.cpp.i
+
+.PHONY : src/audio.i
+
+# target to preprocess a source file
+src/audio.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/audio.cpp.i
+.PHONY : src/audio.cpp.i
+
+src/audio.s: src/audio.cpp.s
+
+.PHONY : src/audio.s
+
+# target to generate assembly for a file
+src/audio.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/audio.cpp.s
+.PHONY : src/audio.cpp.s
+
+src/browse.o: src/browse.cpp.o
+
+.PHONY : src/browse.o
+
+# target to build an object file
+src/browse.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/browse.cpp.o
+.PHONY : src/browse.cpp.o
+
+src/browse.i: src/browse.cpp.i
+
+.PHONY : src/browse.i
+
+# target to preprocess a source file
+src/browse.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/browse.cpp.i
+.PHONY : src/browse.cpp.i
+
+src/browse.s: src/browse.cpp.s
+
+.PHONY : src/browse.s
+
+# target to generate assembly for a file
+src/browse.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/browse.cpp.s
+.PHONY : src/browse.cpp.s
+
+src/dashboard.o: src/dashboard.cpp.o
+
+.PHONY : src/dashboard.o
+
+# target to build an object file
+src/dashboard.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.o
+.PHONY : src/dashboard.cpp.o
+
+src/dashboard.i: src/dashboard.cpp.i
+
+.PHONY : src/dashboard.i
+
+# target to preprocess a source file
+src/dashboard.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.i
+.PHONY : src/dashboard.cpp.i
+
+src/dashboard.s: src/dashboard.cpp.s
+
+.PHONY : src/dashboard.s
+
+# target to generate assembly for a file
+src/dashboard.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/dashboard.cpp.s
+.PHONY : src/dashboard.cpp.s
+
+src/features.o: src/features.cpp.o
+
+.PHONY : src/features.o
+
+# target to build an object file
+src/features.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/features.cpp.o
+.PHONY : src/features.cpp.o
+
+src/features.i: src/features.cpp.i
+
+.PHONY : src/features.i
+
+# target to preprocess a source file
+src/features.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/features.cpp.i
+.PHONY : src/features.cpp.i
+
+src/features.s: src/features.cpp.s
+
+.PHONY : src/features.s
+
+# target to generate assembly for a file
+src/features.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/features.cpp.s
+.PHONY : src/features.cpp.s
+
+src/library.o: src/library.cpp.o
+
+.PHONY : src/library.o
+
+# target to build an object file
+src/library.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/library.cpp.o
+.PHONY : src/library.cpp.o
+
+src/library.i: src/library.cpp.i
+
+.PHONY : src/library.i
+
+# target to preprocess a source file
+src/library.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/library.cpp.i
+.PHONY : src/library.cpp.i
+
+src/library.s: src/library.cpp.s
+
+.PHONY : src/library.s
+
+# target to generate assembly for a file
+src/library.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/library.cpp.s
+.PHONY : src/library.cpp.s
+
+src/main.o: src/main.cpp.o
+
+.PHONY : src/main.o
+
+# target to build an object file
+src/main.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/main.cpp.o
+.PHONY : src/main.cpp.o
+
+src/main.i: src/main.cpp.i
+
+.PHONY : src/main.i
+
+# target to preprocess a source file
+src/main.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/main.cpp.i
+.PHONY : src/main.cpp.i
+
+src/main.s: src/main.cpp.s
+
+.PHONY : src/main.s
+
+# target to generate assembly for a file
+src/main.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/main.cpp.s
+.PHONY : src/main.cpp.s
+
+src/network.o: src/network.cpp.o
+
+.PHONY : src/network.o
+
+# target to build an object file
+src/network.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/network.cpp.o
+.PHONY : src/network.cpp.o
+
+src/network.i: src/network.cpp.i
+
+.PHONY : src/network.i
+
+# target to preprocess a source file
+src/network.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/network.cpp.i
+.PHONY : src/network.cpp.i
+
+src/network.s: src/network.cpp.s
+
+.PHONY : src/network.s
+
+# target to generate assembly for a file
+src/network.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/network.cpp.s
+.PHONY : src/network.cpp.s
+
+src/os.o: src/os.cpp.o
+
+.PHONY : src/os.o
+
+# target to build an object file
+src/os.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/os.cpp.o
+.PHONY : src/os.cpp.o
+
+src/os.i: src/os.cpp.i
+
+.PHONY : src/os.i
+
+# target to preprocess a source file
+src/os.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/os.cpp.i
+.PHONY : src/os.cpp.i
+
+src/os.s: src/os.cpp.s
+
+.PHONY : src/os.s
+
+# target to generate assembly for a file
+src/os.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/os.cpp.s
+.PHONY : src/os.cpp.s
+
+src/players.o: src/players.cpp.o
+
+.PHONY : src/players.o
+
+# target to build an object file
+src/players.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/players.cpp.o
+.PHONY : src/players.cpp.o
+
+src/players.i: src/players.cpp.i
+
+.PHONY : src/players.i
+
+# target to preprocess a source file
+src/players.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/players.cpp.i
+.PHONY : src/players.cpp.i
+
+src/players.s: src/players.cpp.s
+
+.PHONY : src/players.s
+
+# target to generate assembly for a file
+src/players.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/players.cpp.s
+.PHONY : src/players.cpp.s
+
+src/snakeoil.o: src/snakeoil.cpp.o
+
+.PHONY : src/snakeoil.o
+
+# target to build an object file
+src/snakeoil.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.o
+.PHONY : src/snakeoil.cpp.o
+
+src/snakeoil.i: src/snakeoil.cpp.i
+
+.PHONY : src/snakeoil.i
+
+# target to preprocess a source file
+src/snakeoil.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.i
+.PHONY : src/snakeoil.cpp.i
+
+src/snakeoil.s: src/snakeoil.cpp.s
+
+.PHONY : src/snakeoil.s
+
+# target to generate assembly for a file
+src/snakeoil.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/snakeoil.cpp.s
+.PHONY : src/snakeoil.cpp.s
+
+src/snakesys.o: src/snakesys.cpp.o
+
+.PHONY : src/snakesys.o
+
+# target to build an object file
+src/snakesys.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.o
+.PHONY : src/snakesys.cpp.o
+
+src/snakesys.i: src/snakesys.cpp.i
+
+.PHONY : src/snakesys.i
+
+# target to preprocess a source file
+src/snakesys.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.i
+.PHONY : src/snakesys.cpp.i
+
+src/snakesys.s: src/snakesys.cpp.s
+
+.PHONY : src/snakesys.s
+
+# target to generate assembly for a file
+src/snakesys.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/snakesys.cpp.s
+.PHONY : src/snakesys.cpp.s
+
+src/statistics.o: src/statistics.cpp.o
+
+.PHONY : src/statistics.o
+
+# target to build an object file
+src/statistics.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/statistics.cpp.o
+.PHONY : src/statistics.cpp.o
+
+src/statistics.i: src/statistics.cpp.i
+
+.PHONY : src/statistics.i
+
+# target to preprocess a source file
+src/statistics.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/statistics.cpp.i
+.PHONY : src/statistics.cpp.i
+
+src/statistics.s: src/statistics.cpp.s
+
+.PHONY : src/statistics.s
+
+# target to generate assembly for a file
+src/statistics.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/statistics.cpp.s
+.PHONY : src/statistics.cpp.s
+
+src/stdafx.o: src/stdafx.cpp.o
+
+.PHONY : src/stdafx.o
+
+# target to build an object file
+src/stdafx.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.o
+.PHONY : src/stdafx.cpp.o
+
+src/stdafx.i: src/stdafx.cpp.i
+
+.PHONY : src/stdafx.i
+
+# target to preprocess a source file
+src/stdafx.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.i
+.PHONY : src/stdafx.cpp.i
+
+src/stdafx.s: src/stdafx.cpp.s
+
+.PHONY : src/stdafx.s
+
+# target to generate assembly for a file
+src/stdafx.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/stdafx.cpp.s
+.PHONY : src/stdafx.cpp.s
+
+src/task.o: src/task.cpp.o
+
+.PHONY : src/task.o
+
+# target to build an object file
+src/task.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/task.cpp.o
+.PHONY : src/task.cpp.o
+
+src/task.i: src/task.cpp.i
+
+.PHONY : src/task.i
+
+# target to preprocess a source file
+src/task.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/task.cpp.i
+.PHONY : src/task.cpp.i
+
+src/task.s: src/task.cpp.s
+
+.PHONY : src/task.s
+
+# target to generate assembly for a file
+src/task.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/task.cpp.s
+.PHONY : src/task.cpp.s
+
+src/time.o: src/time.cpp.o
+
+.PHONY : src/time.o
+
+# target to build an object file
+src/time.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/time.cpp.o
+.PHONY : src/time.cpp.o
+
+src/time.i: src/time.cpp.i
+
+.PHONY : src/time.i
+
+# target to preprocess a source file
+src/time.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/time.cpp.i
+.PHONY : src/time.cpp.i
+
+src/time.s: src/time.cpp.s
+
+.PHONY : src/time.s
+
+# target to generate assembly for a file
+src/time.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/time.cpp.s
+.PHONY : src/time.cpp.s
+
+src/utils.o: src/utils.cpp.o
+
+.PHONY : src/utils.o
+
+# target to build an object file
+src/utils.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/utils.cpp.o
+.PHONY : src/utils.cpp.o
+
+src/utils.i: src/utils.cpp.i
+
+.PHONY : src/utils.i
+
+# target to preprocess a source file
+src/utils.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/utils.cpp.i
+.PHONY : src/utils.cpp.i
+
+src/utils.s: src/utils.cpp.s
+
+.PHONY : src/utils.s
+
+# target to generate assembly for a file
+src/utils.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/utils.cpp.s
+.PHONY : src/utils.cpp.s
+
+src/version.o: src/version.cpp.o
+
+.PHONY : src/version.o
+
+# target to build an object file
+src/version.cpp.o:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/version.cpp.o
+.PHONY : src/version.cpp.o
+
+src/version.i: src/version.cpp.i
+
+.PHONY : src/version.i
+
+# target to preprocess a source file
+src/version.cpp.i:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/version.cpp.i
+.PHONY : src/version.cpp.i
+
+src/version.s: src/version.cpp.s
+
+.PHONY : src/version.s
+
+# target to generate assembly for a file
+src/version.cpp.s:
+	$(MAKE) -f CMakeFiles/snakeoil_api.dir/build.make CMakeFiles/snakeoil_api.dir/src/version.cpp.s
+.PHONY : src/version.cpp.s
+
+# Help Target
+help:
+	@echo "The following are some of the valid targets for this Makefile:"
+	@echo "... all (the default if no target is provided)"
+	@echo "... clean"
+	@echo "... depend"
+	@echo "... rebuild_cache"
+	@echo "... edit_cache"
+	@echo "... snakeoil_api"
+	@echo "... src/BackEnd.o"
+	@echo "... src/BackEnd.i"
+	@echo "... src/BackEnd.s"
+	@echo "... src/Config.o"
+	@echo "... src/Config.i"
+	@echo "... src/Config.s"
+	@echo "... src/Json.o"
+	@echo "... src/Json.i"
+	@echo "... src/Json.s"
+	@echo "... src/Quotes.o"
+	@echo "... src/Quotes.i"
+	@echo "... src/Quotes.s"
+	@echo "... src/Remote.o"
+	@echo "... src/Remote.i"
+	@echo "... src/Remote.s"
+	@echo "... src/RemoteInterface.o"
+	@echo "... src/RemoteInterface.i"
+	@echo "... src/RemoteInterface.s"
+	@echo "... src/RemoteLMS.o"
+	@echo "... src/RemoteLMS.i"
+	@echo "... src/RemoteLMS.s"
+	@echo "... src/RestWrapper.o"
+	@echo "... src/RestWrapper.i"
+	@echo "... src/RestWrapper.s"
+	@echo "... src/audio.o"
+	@echo "... src/audio.i"
+	@echo "... src/audio.s"
+	@echo "... src/browse.o"
+	@echo "... src/browse.i"
+	@echo "... src/browse.s"
+	@echo "... src/dashboard.o"
+	@echo "... src/dashboard.i"
+	@echo "... src/dashboard.s"
+	@echo "... src/features.o"
+	@echo "... src/features.i"
+	@echo "... src/features.s"
+	@echo "... src/library.o"
+	@echo "... src/library.i"
+	@echo "... src/library.s"
+	@echo "... src/main.o"
+	@echo "... src/main.i"
+	@echo "... src/main.s"
+	@echo "... src/network.o"
+	@echo "... src/network.i"
+	@echo "... src/network.s"
+	@echo "... src/os.o"
+	@echo "... src/os.i"
+	@echo "... src/os.s"
+	@echo "... src/players.o"
+	@echo "... src/players.i"
+	@echo "... src/players.s"
+	@echo "... src/snakeoil.o"
+	@echo "... src/snakeoil.i"
+	@echo "... src/snakeoil.s"
+	@echo "... src/snakesys.o"
+	@echo "... src/snakesys.i"
+	@echo "... src/snakesys.s"
+	@echo "... src/statistics.o"
+	@echo "... src/statistics.i"
+	@echo "... src/statistics.s"
+	@echo "... src/stdafx.o"
+	@echo "... src/stdafx.i"
+	@echo "... src/stdafx.s"
+	@echo "... src/task.o"
+	@echo "... src/task.i"
+	@echo "... src/task.s"
+	@echo "... src/time.o"
+	@echo "... src/time.i"
+	@echo "... src/time.s"
+	@echo "... src/utils.o"
+	@echo "... src/utils.i"
+	@echo "... src/utils.s"
+	@echo "... src/version.o"
+	@echo "... src/version.i"
+	@echo "... src/version.s"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+
diff --git a/API/.build/cmake_install.cmake b/API/.build/cmake_install.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..902b4083259b74ec4605fe6ed2fe6d3cdd6a2432
--- /dev/null
+++ b/API/.build/cmake_install.cmake
@@ -0,0 +1,49 @@
+# Install script for directory: /home/tingjie/src/operating-system/API
+
+# Set the install prefix
+if(NOT DEFINED CMAKE_INSTALL_PREFIX)
+  set(CMAKE_INSTALL_PREFIX "/usr/local")
+endif()
+string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+# Set the install configuration name.
+if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
+  if(BUILD_TYPE)
+    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
+           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
+  else()
+    set(CMAKE_INSTALL_CONFIG_NAME "")
+  endif()
+  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
+endif()
+
+# Set the component getting installed.
+if(NOT CMAKE_INSTALL_COMPONENT)
+  if(COMPONENT)
+    message(STATUS "Install component: \"${COMPONENT}\"")
+    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
+  else()
+    set(CMAKE_INSTALL_COMPONENT)
+  endif()
+endif()
+
+# Install shared libraries without execute permission?
+if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
+  set(CMAKE_INSTALL_SO_NO_EXE "1")
+endif()
+
+# Is this installation the result of a crosscompile?
+if(NOT DEFINED CMAKE_CROSSCOMPILING)
+  set(CMAKE_CROSSCOMPILING "FALSE")
+endif()
+
+if(CMAKE_INSTALL_COMPONENT)
+  set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
+else()
+  set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
+endif()
+
+string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
+       "${CMAKE_INSTALL_MANIFEST_FILES}")
+file(WRITE "/home/tingjie/src/operating-system/API/.build/${CMAKE_INSTALL_MANIFEST}"
+     "${CMAKE_INSTALL_MANIFEST_CONTENT}")
diff --git a/API/.build/snakeoil-rest b/API/.build/snakeoil-rest
new file mode 100755
index 0000000000000000000000000000000000000000..4b373682358da027e987b91cfe58336526a0c9b5
Binary files /dev/null and b/API/.build/snakeoil-rest differ
diff --git a/API/.build/snakeoil_version.h b/API/.build/snakeoil_version.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a8dda05c4e8df1f28a97546bb667c0b084894e6
--- /dev/null
+++ b/API/.build/snakeoil_version.h
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define snakeoil_api_VERSION_MAJOR 
+#define snakeoil_api_VERSION_MINOR 
+#define snakeoil_api_VERSION_PATCH 
diff --git a/API/CMakeLists.txt b/API/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fa2be8b7ee578c9b8a180b056ff254f224eaea80
--- /dev/null
+++ b/API/CMakeLists.txt
@@ -0,0 +1,73 @@
+cmake_minimum_required(VERSION 3.10)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+set(BUILD_SHARED_LIBS OFF)
+set(CMAKE_EXE_LINKER_FLAGS "-static")
+
+set(CODE_NAME "Gear Isolation")
+
+# set the project name
+project(snakeoil_api VERSION 1.2.4 DESCRIPTION "Gear Isolation")
+
+configure_file(version.h.in snakeoil_version.h)
+
+# add target for the Snakeoil library
+add_executable(${PROJECT_NAME} 
+    src/version.cpp
+    src/audio.cpp    
+    src/features.cpp  
+    src/os.cpp       
+    src/RemoteLMS.cpp    
+    src/stdafx.cpp   
+    src/time.cpp     
+    src/Config.cpp     
+    src/main.cpp     
+    src/Remote.cpp           
+    src/snakesys.cpp    
+    src/BackEnd.cpp  
+    src/Json.cpp      
+    src/players.cpp  
+    src/RestWrapper.cpp  
+    src/utils.cpp
+    src/dashboard.cpp  
+    src/network.cpp  
+    src/RemoteInterface.cpp  
+    src/statistics.cpp  
+    src/task.cpp     
+    src/browse.cpp   
+    src/library.cpp   
+    src/Quotes.cpp   
+    src/snakeoil.cpp     
+)
+
+target_include_directories(${PROJECT_NAME} PRIVATE
+  ${PROJECT_BINARY_DIR}
+)
+
+target_include_directories(${PROJECT_NAME} PRIVATE
+  "inc"
+)
+
+target_link_libraries(${PROJECT_NAME} PUBLIC 
+  sqlite3
+  mcrypt
+  cpprest
+  curl
+  b64
+  ssl
+  crypto
+  boost_system
+  dl
+  idn2
+  unistring
+  stdc++
+  pthread
+  m
+  stdc++fs
+  z
+  snakeoil_activate
+)
+
+set_target_properties(${PROJECT_NAME} PROPERTIES
+  OUTPUT_NAME "snakeoil-rest")
diff --git a/API/inc/BackEnd.hpp b/API/inc/BackEnd.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d8256a3cd4a5b58d161084e940b82445e30184e
--- /dev/null
+++ b/API/inc/BackEnd.hpp
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "Config.hpp"
+#include "Json.hpp"
+#include "statistics.hpp"
+#include <map>
+
+class Config;
+class Task;
+
+class BackEnd
+{
+private:
+  /*
+     */
+  BackEnd();
+  ~BackEnd();
+
+  std::map<std::string, web::json::value (*)(const std::string &)> _cbGet,
+      _cbDel,
+      _cbPost;
+
+  /*!
+     */
+  web::json::value latest(const std::string &);
+
+public:
+  /*!
+      Get Singleton obj
+     */
+  static BackEnd *instance();
+
+  static void destroy();
+
+  /*!
+      Return SQLite3 stuffs
+     */
+  Config &config() { return instance()->_config; }
+
+  /*!
+      Return stats object
+     */
+  Statistics &statistics() { return instance()->_stats; }
+
+  // HTTP stuffs;
+  int get(const std::string &api, const std::string &query, web::json::value &);
+  int post(const std::string &api, web::json::value &, const std::string &data);
+  int del(const std::string &api, web::json::value &, const std::string &data);
+
+  std::shared_ptr<Task> getPlayerTask() { return _taskPlayer; }
+  std::shared_ptr<Task> getSnakeoilTask() { return _taskSnakeoil; }
+
+  /*!
+     */
+  std::string translate(const std::string &key);
+
+  /*!
+     */
+  const std::string &getWebRoot() const { return _webroot; }
+
+  /**
+   *
+   * @param skipStartPlayers
+   * @param webroot
+   * @param running
+   */
+  void init(bool skipStartPlayers, const std::string &webroot, bool * running);
+
+  void clearLang() { _currentLang = ""; }
+  bool isRunning() const { return _running == NULL? false: *_running; }
+
+  // returns true if DSD using a kernel that allows me to change fFormat can be changed "on the fly"
+  bool isDSDKernel() const { return _isDSDKernel;}
+
+private:
+  static BackEnd *_be;
+  std::string _webroot;
+  Statistics _stats;
+  Config _config;
+  std::shared_ptr<Task> _taskPlayer,
+      _taskSnakeoil;
+  web::json::value _lang;
+  std::string _noTranslation;
+  std::string _currentLang;
+  int _count;
+  bool _isDSDKernel;
+  bool * _running;
+};
diff --git a/API/inc/Config.hpp b/API/inc/Config.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3b0f03fcb050297bf9eee34483381439e9b84a9
--- /dev/null
+++ b/API/inc/Config.hpp
@@ -0,0 +1,265 @@
+#pragma once
+
+#include <sqlite3.h>
+#include "stdafx.hpp"
+#include <string>
+#include <vector>
+
+class DBWrapper;
+
+class Config
+{
+  private:
+    friend class DBWrapper;
+    sqlite3 *_db;
+    typedef std::map<std::string, std::string> _Datum;
+    typedef std::vector<_Datum> _Data;
+
+    /*!
+      Create DB object
+     */
+    void _getDb();
+
+    /*!
+      Execute SQL statement
+      \param sql SQL Statement
+      \return true on OK
+     */
+    bool _execSQL(const std::string &sql, std::string &errMsg,
+                  Config::_Data *data = nullptr);
+
+    // set database schema
+    void _setSchema(int);
+
+    void _newDb();
+
+    // Database Schemas
+    void _schema0();
+    void _schema1();
+
+    /*!
+      \@param key The key used in setting
+      \return Value
+     */
+    bool _get(const std::string &key, std::string &);
+    bool _get(const std::string &key, web::json::value &);
+    bool _get(const std::string &key);
+
+    bool _set(const std::string &key, const std::string &);
+    bool _set(const std::string &key, const web::json::value &);
+    bool _set(const std::string &key, bool);
+
+    /**
+     * Histrotical table entry. Retrieve audio device.
+     */     
+    web::json::value _getPlayerAudioDevices();
+
+    /**!
+     * To go in schema 5
+     */
+    bool _getPlayerServer(std::string &);
+
+    /**!
+     * To go in schema 5
+     */
+    bool _setPlayerServer(const std::string &);
+
+    bool _getPlayerClient(std::string &);
+    bool _setPlayerClient(const std::string &);
+
+  public:
+    static constexpr const char *LANGUAGE = "language";
+    static constexpr const char *THEME = "theme";
+    static constexpr const char *LAST_CHECK = "last_check";
+    static constexpr const char *REGO_NAME = "rego_name";
+    static constexpr const char *REGO_MAIL = "rego_mail";
+    static constexpr const char *REGO_CODE = "rego_code";
+    static constexpr const char *KERNEL_OPTIONS = "kernel_options";
+    static constexpr const char *CLOCKSOURCE = "clocksource";
+    static constexpr const char *USE_SERVER = "use_server";
+    static constexpr const char *USE_CLIENT = "use_client";
+    static constexpr const char *CUSTOM_AUDIO = "use_custom";
+    static constexpr const char *CUSTOM_CONFIG = "custom_config";
+    static constexpr const char *WIZARD = "wizard";
+
+    static constexpr const char *NETWORK_DNS = "net_dns";
+
+    static constexpr const char *USE_SSH = "use_ssh";
+    static constexpr const char *USE_SAMBA = "use_samba";
+    static constexpr const char *USE_CONSOLE = "use_console";
+    static constexpr const char *USE_STORE_MON = "use_store_mon";
+    static constexpr const char *USE_AVAHI = "use_avahi";
+
+    static constexpr const char *PLAYER_BASIC_MODE = "player_baisc_mode";
+    static constexpr const char *PLAYER_SERVER = "player_server";
+    static constexpr const char *PLAYER_CLIENT = "player_client";
+    static constexpr const char *PLAYER_LIST = "player_list";
+    static constexpr const char *AUDIO_DEVICE = "audio_device";
+    static constexpr const char *AUDIO_OPTION = "audio_option";
+    static constexpr const char *UHUBCTL_ENABLE = "uhubctl_enable";
+    static constexpr const char *USB_OFF = "usb_off";
+
+    static constexpr const char *CPUSET_SHIELD = "cpuset_shield";
+    static constexpr const char *CPUSET_CONFIG = "cpuset_config"; // CPU for system
+
+    static constexpr const char *RAMDISK         = "ramdisk";
+    static constexpr const char *RAMDISK_ENABLE  = "ramdisk_enable";
+    static constexpr const char *RAMDISK_FREE    = "ramdisk_max";
+    static constexpr const char *RAMDISK_TYPE    = "ramdisk_type";
+    static constexpr const char *RAMDISK_SIZE    = "ramdisk_size";
+
+    static constexpr const char *CPUSET_USER_TASKS = "cpuset_user_tasks"; // Tasks in CPUSET->Users
+
+    /*!
+      C'tor
+     */
+    Config();
+
+    /*!
+      D'tor
+     */
+    ~Config();
+
+    /*!
+     */
+    bool getNetDNS(std::string &x);
+    bool setNetDNS(const std::string &x);
+
+    bool getLanguage(std::string &x);
+    bool setLanguage(const std::string &x);
+
+    bool getUsbOff(std::string &x);
+    bool setUsbOff(const std::string &x);
+
+    bool getTheme(std::string &x);
+    bool setTheme(const std::string &x);
+
+    bool getRegoName(std::string &x);
+    bool setRegoName(const std::string &x);
+
+    bool getRegoMail(std::string &x);
+    bool setRegoMail(const std::string &x);
+
+    bool getRegoCode(std::string &x);
+    bool setRegoCode(const std::string &x);
+
+    web::json::value getMusicConfig();
+    bool setMusicConfig(const std::string &x, std::string &errMsg);
+
+    bool getVersionCheckDate(std::string &x);
+    bool setVersionCheckDate(const std::string &x);
+
+    bool getClockSource(std::string &);
+    bool setClockSource(const std::string &);
+
+    bool getKernelOptions(std::string &);
+    bool setKernelOptions(const std::string &);
+
+    bool getServiceSSH();
+    bool setServiceSSH(bool);
+
+    bool getServiceConsole();
+    bool setServiceConsole(bool);
+
+    bool getServiceSamba();
+    bool setServiceSamba(bool);
+
+    bool getServiceStorageMonitor();
+    bool setServiceStorageMonitor(bool);
+
+    bool getServiceAvaHi();
+    bool setServiceAvaHi(bool);
+
+    bool getUseServer();
+    bool setUseServer(bool);
+
+    bool getUseClient();
+    bool setUseClient(bool);
+
+    bool _getCustomConfig(std::string &);
+    bool _setCustomConfig(const std::string &);
+
+    bool getWizard();
+    bool setWizard(bool);
+
+//    bool setPlayerAudioDevices(const web::json::value &);
+//    bool setPlayerAudioOptions(const web::json::value &);
+
+    // web::json::value getPlayerAudioOptions(const strings &playerPaths);
+    void getMacAddress(size_t size, std::string &);
+
+    // return true if input is different from stored value
+    bool setProcPrio(web::json::value);
+
+    // return process priority setup
+    web::json::value getProcPrio();
+
+    // return general CPU config (cpuset)
+    web::json::value getCpuConfig();
+    bool setCpuConfig(web::json::value);
+
+    web::json::value getRamdiskConfig();
+    bool setRamdiskConfig(web::json::value);
+
+    bool getRamdiskEnable();
+    bool setRamdiskEnable(bool);
+    std::string getRamdiskSize();
+    std::string getRamdiskType();
+    
+    /*!
+      Return true if SnakeoilOS is registered
+     */
+    bool isActivated();
+
+    /*!
+      True/False to use uhubctl
+     */
+    bool getUHubCtlEnabled();
+    bool setUHubCtlEnabled(bool);
+
+    /**
+     * Set player runtime config
+     *
+     * @param playerName unique identifier for player name
+     * @param config JSON format config
+     */
+    bool setPlayerRuntimeConfig(const std::string & playerName,
+      const web::json::value & config);
+
+    /**
+     *
+     */
+    bool getPlayerRuntimeConfig(const std::string & playerName,
+      web::json::value & config);
+
+    /**
+      Get all player config
+      @param allConfig all player config
+     */
+    bool getAllPlayersRuntimeConfig(web::json::value & allConfig);
+
+    /**!
+      Set all player config
+      */
+    bool setAllPlayersRuntimeConfig(const web::json::value &);
+
+    /**
+     * Return if player menu should be in basic mode or not
+     */
+    bool getPlayerBasicMode();
+
+    /**
+     * Set player menu should be in basic mode or not
+     */
+    bool setPlayerBasicMode(bool basic);
+
+    /**
+     * Set players to start
+     */
+    bool setPlayersToStart(const web::json::value & v);
+
+    /**
+      Get players to start
+     */
+    bool getPlayersToStart(web::json::value & players);
+};
diff --git a/API/inc/Json.hpp b/API/inc/Json.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..61147e18d25f37f9331a36702e1a7202d5307515
--- /dev/null
+++ b/API/inc/Json.hpp
@@ -0,0 +1,36 @@
+#pragma once
+#include "stdafx.hpp"
+#include <vector>
+
+class Json;
+typedef std::vector<Json> Jsons;
+
+class Json
+{
+private:
+  web::json::value _json;
+
+public:
+  /*!
+      C'tor
+     */
+  Json();
+  Json(const strings &keys, const strings &values);
+  explicit Json(const strings &values);
+
+  void append(const std::string &key, const std::string &value);
+  void append(const std::string &key, int);
+  void append(const std::string &key, web::json::value);
+  void append_bool(const std::string &key, bool);
+  void append(const std::string &key, std::vector<int> &);
+
+  void addChild(const std::string &childName, Jsons &list); //XXX_TJ: Gotta fix this
+  void addChild(const std::string &childName, Json &obj);
+  void addChild(const std::string &childName, web::json::value obj);
+  void addChild(const std::string &childName, const strings &keys, const strings &values);
+
+  /*!
+      Return a copy of value, (Or should this be reference?)
+     */
+  web::json::value &value();
+};
diff --git a/API/inc/Quotes.hpp b/API/inc/Quotes.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..259d801a1f6824c2bd27b54ab602e42b5104e6d2
--- /dev/null
+++ b/API/inc/Quotes.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "stdafx.hpp"
+#include <string>
+
+class Quotes
+{
+private:
+  typedef struct Quote
+  {
+    std::string quote,
+        author,
+        url;
+
+    Quote(const std::string &q, const std::string &a, const std::string &u = "")
+        : quote(U(q)),
+          author(U(a)),
+          url(U(u)) {}
+
+    /*
+      Copy constructor
+    */
+    Quote(const Quote &rhs)
+        : quote(rhs.quote),
+          author(rhs.author),
+          url(rhs.url) {}
+  } Quote;
+
+  std::vector<Quote> _quotes;
+  std::vector<Quote>::const_iterator _it;
+
+public:
+  /*!
+      Constructor
+     */
+  Quotes();
+  ~Quotes();
+
+  /*!
+      get quote. This generates a new quote everytime.
+     */
+  const std::string &getQuote();
+
+  /*!
+      get the author of quote from getQuote()
+     */
+  const std::string &getAuthor() const;
+  const std::string &getURL() const;
+};
diff --git a/API/inc/Remote.hpp b/API/inc/Remote.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0031aabc4bfa78acf903d4e5896f69219a6be63f
--- /dev/null
+++ b/API/inc/Remote.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "RemoteInterface.hpp"
+
+/*
+ */
+class Remote
+{
+public:
+  static RemoteInterface *getRemote();
+};
diff --git a/API/inc/RemoteInterface.hpp b/API/inc/RemoteInterface.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..34364fa14c93819292535edf9ef2e35e6bb9d7df
--- /dev/null
+++ b/API/inc/RemoteInterface.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "strings.hpp"
+#include <vector>
+
+typedef struct FileItem
+{
+  const std::string name; // full path name
+  //bool isFile;             // true if name is file
+} FileItem;
+
+typedef std::vector<FileItem> FileItems;
+
+/*
+  This defines the interface every web remote must adhere to
+ */
+class RemoteInterface
+{
+public:
+  /*
+      C'tor
+     */
+  RemoteInterface();
+  /*!
+      D'tor
+    */
+  virtual ~RemoteInterface();
+
+  /* Interfaces */
+  /*
+     */
+  virtual void getFolder(const std::string &path, FileItems &fileItems) = 0;
+};
diff --git a/API/inc/RemoteLMS.hpp b/API/inc/RemoteLMS.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1b4de6ee7f1f0a21b05ac47d315f3088b64012b5
--- /dev/null
+++ b/API/inc/RemoteLMS.hpp
@@ -0,0 +1,11 @@
+#include "RemoteInterface.hpp"
+
+/*
+ */
+class RemoteLMS : public RemoteInterface
+{
+public:
+  RemoteLMS();
+
+  virtual void getFolder(const std::string &path, FileItems &fileItems);
+};
diff --git a/API/inc/RestWrapper.hpp b/API/inc/RestWrapper.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..105e33d28e67aaf130b9a1b4a5ffd183b197226f
--- /dev/null
+++ b/API/inc/RestWrapper.hpp
@@ -0,0 +1,23 @@
+#pragma once
+#include "stdafx.hpp"
+
+class RestWrapper
+{
+public:
+  RestWrapper() {}
+  explicit RestWrapper(utility::string_t url);
+
+  pplx::task<void> open() { return m_listener.open(); }
+  pplx::task<void> close() { return m_listener.close(); }
+
+private:
+  void handle_get(web::http::http_request message);
+  void handle_put(web::http::http_request message);
+  void handle_post(web::http::http_request message);
+  void handle_delete(web::http::http_request message);
+
+  web::http::experimental::listener::http_listener m_listener;
+
+private:
+  static void _reply(int, web::http::http_request, const web::json::value &value, bool debug = false);
+};
diff --git a/API/inc/audio.hpp b/API/inc/audio.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d2ed3a94ab76ef84b91dcbab9ae8b47b67e8b503
--- /dev/null
+++ b/API/inc/audio.hpp
@@ -0,0 +1,65 @@
+#pragma once
+#include "stdafx.hpp"
+#include "strings.hpp"
+
+namespace audio
+{
+  static constexpr const char * ALSA           = "alsa";
+  static constexpr const char *RAVENNA         = "ravenna";
+  static constexpr const char *RAVENNA_PRESENT = "present";
+  static constexpr const char *RAVENNA_PROTOCOL= "protocol";
+  static constexpr const char *RAVENNA_HOST    = "host";
+  static constexpr const char *RAVENNA_PORT    = "port";
+  static constexpr const char *RAVENNA_SOFTWARE= "/var/alsa-aes67-driver/Merging_RAVENNA_Daemon";
+
+  /*!
+    Start Ravenna client
+   */
+  void startRavennaClient();
+
+  /*!
+    Stop Ravenna Client
+   */
+  void stopRavennaClient();
+
+  /*!
+    Get list of Audio cards
+   */
+  void getAudioCards(strings &cards);
+
+  // get ALSA version
+  void getVersion(std::string &);
+
+  /*!
+    Returns true if a Ravenna audio driver is present
+   */
+  web::json::value getRavennaInfo();
+
+  /*!
+   */
+  web::json::value getAudioCards();
+
+  /*!
+   */
+  web::json::value getStatus();
+
+  /*!
+      Uninstall PulseAudio
+     */
+  web::json::value removePulse(const std::string &);
+
+  /*!
+    Get First USB DAC's USB ID
+   */
+  web::json::value getUsbId(const std::string &);
+
+  /*!
+    Get DSD configuration
+   */
+  web::json::value getDsdConfig(const std::string &);
+
+  /*!
+    set DSD Configuration
+   */
+  void setDsdConfig(web::json::value & v);
+} // namespace audio
diff --git a/API/inc/browse.hpp b/API/inc/browse.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..083b4af06097c73ef3ab80337df39f3bcea7111d
--- /dev/null
+++ b/API/inc/browse.hpp
@@ -0,0 +1,42 @@
+#pragma once
+#include "stdafx.hpp"
+
+class Browse {
+  enum {
+    FOLDER,
+    MUSIC,
+    PLAYLIST,
+    PICTURE  
+  };
+
+  public:
+    /*!
+     */
+    static web::json::value getFolderContents(web::json::value v);
+
+    /*!
+      Create folder
+     */
+    static web::json::value createFolder(web::json::value v);
+
+    /*!
+      Add these files to the media library
+     */
+    static web::json::value addFiles(web::json::value v);
+
+    /*!
+      Delete these files from the media library
+     */
+    static web::json::value delFiles(web::json::value v);
+
+    /*!
+      Copy Files to RAM
+     */
+    static web::json::value copyFiles(web::json::value v);
+
+    /*!
+      Replace Files in RAM with these files
+     */
+    static web::json::value replaceFiles(web::json::value v);
+};
+
diff --git a/API/inc/dashboard.hpp b/API/inc/dashboard.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..12b1d33a8f444d64f7c0e252acceac0bda519699
--- /dev/null
+++ b/API/inc/dashboard.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "strings.hpp"
+#include "stdafx.hpp"
+
+namespace dashboard
+{
+web::json::value qotd();
+
+web::json::value getElements();
+} // namespace dashboard
diff --git a/API/inc/features.hpp b/API/inc/features.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7745a187291ad6d61778a477c58873ccfa848e39
--- /dev/null
+++ b/API/inc/features.hpp
@@ -0,0 +1,42 @@
+#pragma once
+#include "stdafx.hpp"
+class Json;
+
+class Features
+{
+public:
+  /*
+      Returns true if Snakeoil OS is activated edition
+     */
+  static bool isActivated();
+
+  /*!
+      Returns true if CGroup is available
+     */
+  static bool hasCGroup();
+
+  /*!
+      Returns true if CPUSet tools are available
+     */
+  static bool hasCPUSet();
+
+  /*!
+      Returns true if exFAT file system is supported
+     */
+  static bool hasFSExFat();
+
+  /*!
+      Returns true if ecasound is installed
+     */
+  static bool hasEcaSound();
+
+  /*!
+      get Snakeoil features (CPPrestsdk edition)
+     */
+  static void getFeatures(web::json::value &v);
+
+  /*!
+      get Snakeoil Features list (Json edition)
+     */
+  static void getFeatures(Json &v);
+};
diff --git a/API/inc/library.hpp b/API/inc/library.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ba09ec52660e224f23ad37fae8e0e8be676ed48
--- /dev/null
+++ b/API/inc/library.hpp
@@ -0,0 +1,21 @@
+#pragma once
+#include "stdafx.hpp"
+#include "utils.hpp"
+
+namespace library
+{
+std::string getMounted();
+std::string getUnmounted();
+
+void getUninitialised(strings &);
+std::string getCredentialsCifs();
+
+/*!
+    \return true if credentials are updated
+   */
+bool setCredentialsCifs(const std::string &username, const std::string &password, const std::string &domain);
+
+bool initDisk(const std::string &, std::string &);
+
+web::json::value saveConfig(const std::string &);
+} // namespace library
diff --git a/API/inc/network.hpp b/API/inc/network.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d1bc89cd9fb9d7a1fa0d6f98724eb08e7cee9f7f
--- /dev/null
+++ b/API/inc/network.hpp
@@ -0,0 +1,31 @@
+/*!
+  All networking functions here
+*/
+#pragma once
+#include "utils.hpp"
+
+namespace network
+{
+void getNICs(strings &);
+
+//
+void getNIC(const std::string &interface, strings &keys, strings &values);
+std::string getIPV4(const std::string &);
+std::string getIPV4Mask(const std::string &);
+std::string getIPV4MTU(const std::string &);
+std::string getMode(const std::string &);
+std::string getHostname();
+std::string getGateway();
+std::string getDNS();
+
+// set up network
+void init();
+
+/*!
+    Save network setting
+    \param data JSON data
+    \param msg any error message to return
+    \return Can't remember what this does
+   */
+int setNetworkConfig(const std::string &data, std::string &msg);
+} // namespace network
diff --git a/API/inc/os.hpp b/API/inc/os.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..07440e4222701155d2ca45ab442b27dd3cd62931
--- /dev/null
+++ b/API/inc/os.hpp
@@ -0,0 +1,214 @@
+#pragma once
+#include "stdafx.hpp"
+
+#include <pplx/pplxlinux.h>
+class Task;
+
+class OS
+{
+private:
+  OS();
+  ~OS();
+  static int _mount;
+
+public:
+  typedef enum FORMAT
+  {
+    FORMAT_OLD_FIRMWARE,
+    FORMAT_FIRMWARE,
+    FORMAT_MODULE,
+    FORMAT_UNKNOWN
+  } Format;
+
+  /*!
+    Look at PHP configuration, and update any limits that's under
+    \parameter max Upload limit in megabytes
+   */
+  static void fixPhpUploadLimit(int max);
+
+  /*!
+      check if file exists
+      \param name filename (includes path)
+      \return true if file name exists
+     */
+  static bool exists(const std::string &name);
+
+  /*!
+    Return a string describing the CPU architecture
+   */
+  static const std::string & getArch();
+
+  /*!
+    Delete the file
+   */
+  static void del(const std::string &name);
+
+  /*!
+    umount a directory
+   */
+  static void umount(web::json::value);
+
+  /*!
+      mount a series of directories
+      \return true on error
+     */
+  static int mount(web::json::value mount, std::string &msg);
+
+  /*!
+      Create directory
+     */
+  static void mkDir(const std::string &, __mode_t umask = 0777);
+
+  /*!
+    Move file from SRC to DST
+
+    \param src Source file
+    \param dst Destination file
+   */
+  static void move(const std::string & src, const std::string & dst);
+
+  /*!
+      Execute shell command
+
+      \param cmd command to execute
+      \param result output from stdout
+      \return return value of shell command
+     */
+  static int exec_wait(const std::string &cmd, std::string &result);
+  static int exec_wait(const std::string &cmd, const std::shared_ptr<Task> &);
+
+  /*!
+      Execute shell command
+
+      \param cmd command to execute
+      \param results output from stdout, broken up into strings specified by delimiter
+      \param delim the delimiter to use to break the strings into
+      \return return value of shell command
+     */
+  static int exec_wait(const std::string &cmd, strings &results, char delim = '\n');
+
+  /*!
+      Run cmd in the background. Output will be returned as console.
+
+      \param cmd command line to execute
+      \param wait Wait message
+      \param msg console output
+     */
+  static int exec_nowait(const std::string &cmd, const std::string &wait, std::string &msg);
+
+  /*!
+      Run cmd in the background. Output will be returned as console.
+
+      \param cmd command line to execute
+      \param task console output
+     */
+  static int exec_nowait(const std::string &cmd, std::shared_ptr<Task> task);
+
+  /*!
+      Just run cmd in the background. Ignore output.
+     */
+  static int exec_nowait(const std::string &cmd);
+  /*!
+      Get list of jobs that are executing
+     */
+  static void getTasks(std::vector<int> &);
+
+  /*!
+      Get the Task object for ticket
+     */
+  static const Task &getTask(int ticket);
+
+  /*!
+      Remove a task
+     */
+  static void removeTask(int ticket);
+
+  /*!
+      Save Text File.
+      \return true if saving is performed. false otherwise (e.g. same contents)
+     */
+  static bool saveTextFile(const std::string &fn, const std::string &contents);
+
+  /*!
+      Read text file and place it in contents
+      \return true on failure, false otherwise
+     */
+  static bool readTextFile(const std::string &fn, std::string &contents);
+
+  /*!
+      Return true if in debug mode
+     */
+  static bool debug();
+
+  static std::shared_ptr<Task> getTicketOutput();
+  static int setTicketDone(std::shared_ptr<Task>, std::string &msg);
+
+  /*!
+      Decrypt input file
+
+      \return ENUM TYPE format
+     */
+  static OS::Format decrypt(const std::string &inFile, const std::string &outFile, std::shared_ptr<Task>);
+
+  static bool compatible(const std::string &fn);
+
+  static void updateGrub(const std::shared_ptr<Task> &,
+                         std::string &version, std::string &clock, std::string &opts);
+
+  static web::json::value getAvailClocksource();
+  static std::string getClocksource();
+
+  static std::string getKernelOptions();
+  static web::json::value getAvailKernelOptions();
+
+  static std::string getBootKernel(); // get current boot kernel
+  static std::string getGrubKernel(); // get grub kernel
+  static web::json::value getAvailBootKernels();
+
+  /*!
+    Stop uhubctl from running
+   */
+  static web::json::value stopUhubCtl();
+
+  /*!
+      Get All USB ports
+     */
+  static web::json::value getUSBPorts(bool read = true);
+
+  /*!
+      Turn on/off USB ports based on what's defined in v
+      \param v json object defined the vendor and port number of USB ports
+      \param off extracted USB ports to poweroff from v
+     */
+  static bool setUSBPorts(web::json::value v, std::string &off);
+
+  static web::json::value resetUSB();
+
+  /*!
+    Return the free RAM available
+    @return free RAM in Megabytes
+  */
+  static int getFreeRAM();
+  static void mountRamdisk();
+  static void unmountRamdisk();
+
+  /*!
+    Returns true if RAmdisk is mounted ok
+   */
+  static bool isRamdiskOK();
+
+  /*!
+    Return disk used in /media/music/ram
+    @return disk used, in MB
+   */
+  static int getRamdiskUsed();
+
+
+private:
+  static int _count;
+  typedef std::map<int, std::shared_ptr<Task>> _Tasks;
+  static _Tasks _tasks;
+  static pplx::details::reader_writer_lock_impl _lock;
+  static Task _empty;
+  static std::string _arch;
+};
diff --git a/API/inc/players.hpp b/API/inc/players.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f944198596f3424416af2827bbd449265beb7e31
--- /dev/null
+++ b/API/inc/players.hpp
@@ -0,0 +1,130 @@
+#pragma once
+
+#include "stdafx.hpp"
+class Task;
+
+typedef struct SetupConfig
+{
+  int order;
+  int server;
+  std::string path;
+  std::string name;
+  std::string init;
+  std::string program;
+  std::string group;
+  std::string info;
+  bool manual;
+  bool vnc;
+  bool has_client;
+  bool alsa_setup;
+  bool wizard;
+  bool has_options;
+  bool has_mac_adr;
+  bool installed;
+  bool custom_audio;
+
+  std::string config;
+  std::string start;
+  std::string stop;
+  std::string help;
+  std::string install;
+  std::string uninstall;
+  std::string remote;
+  strings client_list;
+
+  SetupConfig() { manual = vnc = server = installed = order = alsa_setup = has_options = has_mac_adr = has_client = wizard = custom_audio = 0; }
+} SetupConfig;
+
+typedef std::multimap<int, SetupConfig> SetupConfigs;
+
+class Players
+{
+  std::map<std::string, int> _lookup;
+
+private:
+  Players();
+
+  /**
+   *
+   */
+  static bool _start(size_t num, const SetupConfig &pc, const std::string &env,
+                     std::shared_ptr<Task>);
+
+  static bool _stop(const SetupConfig &pc, std::shared_ptr<Task>);
+
+  /**
+   * @param status Input playerpath here, and it will be replaced with the status of the player. XXX_TJ: This is bad design, should fix!
+   * @return player name
+   */
+  static const std::string _getStatusAux(std::shared_ptr<Task> task, std::string &status,
+                            std::string &remote, std::string &err, bool &error, bool & installed);
+
+  /*!
+      Read player names of every available player
+     */
+  static void _getPlayerNames(strings &names);
+
+public:
+  static constexpr const char *PATH_PLAYERS = "/var/www/players/";
+
+  /*!
+      /param all true if you want to list everything. False will only return
+             server and client info. Note when all flag is used all players
+             will be placed in server
+     */
+  static web::json::value getPlayers(bool all = false);
+
+  /*!
+      Return players configuration (REST API call)
+     */
+  static web::json::value getConfig();
+
+  /*!
+      Set players configuration (REST API call)
+     */
+  static web::json::value setConfig(const std::string &data);
+
+  /*!
+      Stop the players
+     */
+  static void stop();
+
+  /**
+   * Start the players
+   * @param errMsg Error message
+   * @return true on error, false otherwise
+   */
+  static bool start(std::string & errMsg);
+
+  /*!
+      Call the ALSA unmute script to unmute all audio output devices
+     */
+  static web::json::value unmute();
+
+  /*!
+      Return the ALSA output status
+     */
+  static web::json::value getStatus();
+
+  /**
+   * Return if player basic mode is set or not
+   */
+  static web::json::value getBasicMode();
+
+  /**
+   * Set player basic mode
+   */
+  static web::json::value setBasicMode(const std::string &);
+
+  /*!
+      Call by the backend's init
+     */
+  static void init();
+
+  /*!
+      Get player configuration
+
+      \return true if executable exists (will be shown), false otherwise (not shown)
+     */
+  static bool getSetupConfig(const std::string &playerPath, SetupConfig &config);
+};
diff --git a/API/inc/snakeoil.hpp b/API/inc/snakeoil.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..17cd8c4c8557c997d59dfae84db7fdd2b1513626
--- /dev/null
+++ b/API/inc/snakeoil.hpp
@@ -0,0 +1,70 @@
+#pragma once
+#include "stdafx.hpp"
+
+#include <string>
+
+namespace snakeoil
+{
+enum
+{
+  NO_CHANGES = 0,
+  REBOOT_REQUIRED = 1,
+  SMB = 2,
+  CON = 4,
+  SSH = 8,
+  MON = 16,
+  AVA = 32,
+  PROCESS = 64,
+  KERNEL = 128,
+  SOFTWARE = 256,
+  USB = 512,
+  DSD = 1024,
+  RAMDISK=2048,
+};
+
+bool parseActivationDetails(const std::string &, const std::string &, const std::string &, std::string &msg);
+
+// Get Snakeoil Software settings
+web::json::value getSoftware(const std::string &);
+
+// Get Snakeoil services settings
+web::json::value getServices(const std::string&);
+
+// Get Snakeoil kernel settings
+web::json::value getKernel(const std::string &);
+
+// Get Snakeoil Hardware
+web::json::value getHardware(const std::string &);
+
+// split getUSB to another call as it's slower
+web::json::value getUSBPorts(const std::string &);
+
+// Save Snakeoil software settings
+web::json::value postSoftware(const std::string &data);
+
+// save Snakeoil services
+web::json::value postServices(const std::string&data);
+
+// save snakeoil kernel
+web::json::value postKernel(const std::string & data);
+
+// save hardware info
+web::json::value postHardware(const std::string & data);
+
+/*
+    \param sleep wait sleep seconds first before changing priority
+   */
+void chprio(int sleep = 0);
+
+/*!
+    Power off USB
+   */
+void powerOffUsb();
+
+void startStopServices(bool x = true);
+void startStopSSH(bool);
+void startStopSMB(bool);
+void startStopCON(bool);
+void startStopAVA(bool);
+void startStopCpuset(bool);
+} // namespace snakeoil
diff --git a/API/inc/snakesys.hpp b/API/inc/snakesys.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..169f44d0ef5ac93ae0d35e3ba27b9d2461ed1298
--- /dev/null
+++ b/API/inc/snakesys.hpp
@@ -0,0 +1,43 @@
+#pragma once
+#include "stdafx.hpp"
+#include "Json.hpp"
+#include <string>
+
+namespace snakesys
+{
+std::string getSnakeoilUser();
+
+web::json::value shutdown();
+
+web::json::value reset();
+web::json::value clearCache();
+
+web::json::value getSystemDiagnostics(const std::string &file);
+
+web::json::value getSystemTop();
+web::json::value getSystemNetstat();
+
+web::json::value runCyclicTest();
+
+web::json::value getTasks();
+
+web::json::value getJobOutput(int code);
+void removeTask(int code);
+
+web::json::value update_snakeoil(const std::string &data);
+web::json::value update_ubuntu(const std::string &data);
+web::json::value upgrade_ubuntu(const std::string & data);
+web::json::value resetPassword(const std::string &data);
+web::json::value upload(const std::string & data);
+
+//web::json::value test(const std::string & data);
+
+web::json::value getLanguage(const std::string &data);
+web::json::value getLanguageItems(const std::string &data);
+web::json::value setLanguageItems(const std::string &data);
+
+web::json::value backupSnakeoilConfig(const std::string & data);
+web::json::value restoreSnakeoilConfig(const std::string & data);
+
+web::json::value getLastUpdateCheck();
+} // namespace snakesys
diff --git a/API/inc/statistics.hpp b/API/inc/statistics.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..205c48a301b26469d179c5aff0fb20e20dd4de77
--- /dev/null
+++ b/API/inc/statistics.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include "stdafx.hpp"
+#include <deque>
+
+class Statistics
+{
+public:
+  Statistics();
+
+  /*
+      Call this to sample the current state
+     */
+  void sample();
+
+  /*!
+      Return stats object
+     */
+  void latest(web::json::value &v);
+
+private:
+  // everything is stored in percentage
+  std::deque<double> _ram_used,
+      _ram_free,
+      _ram_cached;
+};
diff --git a/API/inc/stdafx.hpp b/API/inc/stdafx.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..936f2acc9ef0da79674d392dfdd75360e8871038
--- /dev/null
+++ b/API/inc/stdafx.hpp
@@ -0,0 +1,35 @@
+/***
+* Copyright (C) Microsoft. All rights reserved.
+* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+*
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* stdafx.h : include file for standard system include files,
+* or project specific include files that are used frequently,
+* but are changed infrequently
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+#pragma once
+#include <stdlib.h>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+#include <random>
+
+#ifdef _WIN32
+#define NOMINMAX
+#include <Windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "cpprest/json.h"
+#include "cpprest/http_listener.h"
+#include "cpprest/uri.h"
+#include "cpprest/asyncrt_utils.h"
+
+typedef std::vector<std::string> strings;
diff --git a/API/inc/strings.hpp b/API/inc/strings.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9575d98b471f198c46f267760daa38431ec5fe89
--- /dev/null
+++ b/API/inc/strings.hpp
@@ -0,0 +1,5 @@
+#pragma once
+#include <string>
+#include <vector>
+
+typedef std::vector<std::string> strings;
diff --git a/API/inc/task.hpp b/API/inc/task.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..85bf6f32888d27902578b7e3c27244218026a473
--- /dev/null
+++ b/API/inc/task.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include <string>
+#include <sstream>
+
+class Task
+{
+public:
+  int code;
+  bool done;
+  bool userFlag;
+  bool restartWeb;
+
+  std::string cmd, //!< Command line to execute
+      wait;        //!< Waiting message to show if execution hasn't finished
+  std::ostringstream console;
+
+  Task();
+  explicit Task(const std::string &w);
+};
diff --git a/API/inc/time.hpp b/API/inc/time.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4b18bc9a4f3da69a36ee7e336e22e43dd0813c59
--- /dev/null
+++ b/API/inc/time.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include <time.h>
+#include <string>
+
+class Time
+{
+public:
+  // current time object
+  Time();
+
+  // time based on t
+  explicit Time(const std::string &t);
+
+  /*!
+     */
+  const std::string &toString() const;
+
+  double operator-(const Time &t) const;
+
+private:
+  time_t _time_t;
+  std::string _str;
+
+  void _toString();
+};
diff --git a/API/inc/utils.hpp b/API/inc/utils.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..86d74cbb851eb717d2964c0a50a289539af69d4f
--- /dev/null
+++ b/API/inc/utils.hpp
@@ -0,0 +1,69 @@
+#pragma once
+#include "strings.hpp"
+
+namespace utils
+{
+  /*!
+    Create file based on formData input
+
+    @param formData form data input
+    @param errMsg Any error message returned here
+    @return true on error
+   */
+  bool createUploadedFile(const std::string & formData, std::string & errMsg);
+
+  /*!
+    Fix release upgrade file
+   */
+  void fixReleaseUpgrade();
+
+  /*!
+   * change ownership of path to new owner and group
+    \param  path Path to chown
+    \param owner New owner
+    \param group new group
+  */
+  void fixOwnerGroup(const std::string & path, const std::string & owner, const std::string & group);
+
+  /*!
+      Trim left of string of whitespace
+   */
+  std::string &ltrim(std::string &s);
+
+  // trim from end
+  std::string &rtrim(std::string &s);
+
+  /*
+     trim whitespace from both ends
+   */
+  std::string &trim(std::string &s);
+
+  /*
+    Replace all instances of \n with <br />
+   */
+  std::string &markup(std::string &);
+
+  /*!
+    Break in into a vector of strings in out, delimited by delim
+   */
+  void tokenise(const std::string &in, strings &out, char delim = '\n');
+
+  /*!
+    Return a substring.
+   */
+  std::string &substr(std::string &, char split);
+
+  /*!
+    Go through input, and replace all instances of from and to 'to'.
+   */
+  std::string &replace(std::string &input, const std::string &from, const std::string &to);
+
+  // remove leading and trailing '' or ""
+  std::string &unquote(std::string &);
+
+  // generate a series(length size) of unique mac address, delimited by ,
+  void getMacAddress(std::string &, int size);
+
+  // Clean up \r in messages
+  void cleanLineFeed(const std::string & input, std::string & cleaned);
+} // namespace utils
diff --git a/API/inc/version.hpp b/API/inc/version.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec53fe773f8aa475308891502fe1cf2c473f8526
--- /dev/null
+++ b/API/inc/version.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "stdafx.hpp"
+#include <vector>
+#include <string>
+
+class Version
+{
+public:
+  /*!
+      Returns the current version of Snakeoil OS
+     */
+  static const std::string &getVersion();
+
+  /*!
+      Returns true if there is an update
+      \param param { MAJOR: x, MINOR: x, PATCH: x, RELEASE x}
+     */
+  static bool hasUpdate(web::json::value &param);
+
+private:
+  static std::vector<int> _bits;
+  static const std::string _version;
+  enum
+  {
+    MAJOR,
+    MINOR,
+    PATCH,
+    RELEASE,
+    LAST
+  };
+};
diff --git a/API/src/BackEnd.cpp b/API/src/BackEnd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c8f917b8c17bdbd042929e1cf767755c062e8147
--- /dev/null
+++ b/API/src/BackEnd.cpp
@@ -0,0 +1,1030 @@
+#include "BackEnd.hpp"
+
+#include "dashboard.hpp"
+#include "network.hpp"
+#include "library.hpp"
+#include "audio.hpp"
+#include "players.hpp"
+#include "snakeoil.hpp"
+#include "snakesys.hpp"
+#include "version.hpp"
+#include "browse.hpp"
+#include "os.hpp"
+#include "time.hpp"
+#include "task.hpp"
+#include "features.hpp"
+#include <string>
+#include <algorithm>
+
+using namespace std;
+using namespace web::http;
+using namespace web;
+
+/*
+  /return true on success, and false otherwise
+ */
+static bool _aux(const string &api, json::value &obj,
+                 map<string, json::value (*)(const string &)> &cb, const string &data = "")
+{
+  auto iterator = cb.find(api);
+  if (iterator == cb.end())
+    return false;
+
+  obj = (*(iterator->second))(data);
+
+  return true;
+}
+
+json::value _getFeaturesActivated(const string &);
+json::value _getPong(const string &);
+json::value _getDebug(const string &);
+json::value _getVersion(const string &);
+json::value _getFeatures(const string &);
+json::value _getUsbId(const string &);
+json::value _getQuote(const string &);    // get QOTD
+json::value _getDashboardElements(const string &);    // get System info
+json::value _getLanguage(const string &); // getLanguage
+json::value _getTheme(const string &);
+json::value _getNetworkInterface(const string &);
+json::value _getNetworkConfig(const string &);
+json::value _getLibraryConfig(const string &);
+json::value _getLibraryStatus(const string &);
+json::value _getHardwareStatus(const string &);
+json::value _getPlayerBasicMode(const string &);
+json::value _getPlayerRemovePulse(const string &);
+json::value _getPlayersInstalled(const string &);
+json::value _getSetupConfig(const string &);
+json::value _getPlayerStatus(const string &);
+json::value _getPlayerUnmute(const string &);
+json::value _getSetupUser(const string &);
+json::value _getSystemClearCache(const string &);
+json::value _getSystemTop(const string &);
+json::value _getSystemNetstat(const string &);
+json::value _getSystemRunningTasks(const string &);
+json::value _getSnakeoilCheckVersion(const string &);
+json::value _getSnakeoilCheckDate(const string &);
+json::value _getSnakeoilSoftware(const string &);
+json::value _getSnakeoilServices(const string &);
+json::value _getSnakeoilKernel(const string &);
+json::value _getSnakeoilHardware(const string &);
+json::value _getSnakeoilUSB(const string &);
+json::value _getWizard(const string &);
+json::value _getLicense(const string &);
+json::value _getLogs(const string &);
+json::value _getRamdisk(const string &);
+json::value _getStatisticsLatest(const string &);
+json::value _getStopUhubctl(const string &);
+json::value _getBackupSnakeoilConfig(const string &);
+
+json::value _postSystemUpload(const string &);
+json::value _postSystemShutdown(const string &);
+json::value _postSystemLanguage(const string &);
+json::value _postSystemLanguageEdit(const string &);
+json::value _postSystemLanguageSave(const string &);
+json::value _postSystemTheme(const string &);
+json::value _postSystemCyclicTest(const string &);
+json::value _postSystemReset(const string &);
+json::value _postSystemDiagnostics(const string &);
+json::value _postSystemTasks(const string &);
+json::value _postSystemResetPassword(const string &);
+json::value _postSystemRestartBE(const string &);
+json::value _postSystemResetUSB(const string &);
+json::value _postSystemRestore(const string &);
+json::value _postNetworkConfig(const string &);
+json::value _postLibraryFormat(const string &);
+json::value _postLibraryConfig(const string &);
+json::value _postSetupConfig(const string &);
+json::value _postSetupUpdate(const string &);
+json::value _postSnakeoilActivate(const string &);
+json::value _postSnakeoilSoftware(const string &);
+json::value _postSnakeoilServices(const string &);
+json::value _postSnakeoilKernel(const string &);
+json::value _postSnakeoilHardware(const string &);
+json::value _postSystemKillTasks(const string &);
+json::value _postWizard(const string &);
+json::value _postUpdateUbuntu(const string &);
+//json::value _postUpgradeUbuntu(const string &);
+//json::value _postTest(const string &);
+json::value _postBrowseCreateFolder(const string &);
+json::value _postBrowseAddFiles(const string &);
+json::value _postBrowseDelFiles(const string &);
+json::value _postBrowseCopyToRam(const string &);
+json::value _postBrowseReplaceRam(const string &);
+json::value _postFolderContents(const string &);
+json::value _postPlayerBasicMode(const string &);
+
+
+void extractTheme();
+
+BackEnd::BackEnd()
+    : _taskPlayer(make_shared<Task>()), 
+      _taskSnakeoil(make_shared<Task>()),
+      _count(0),
+      _isDSDKernel(false),
+      _running(NULL)
+{
+  ucout << U("Starting Snakeoil OS RESTful Server ") << U(Version::getVersion()) << endl;
+
+  // register callbacks
+  // GET
+  _cbGet["/features/activated"] = &_getFeaturesActivated;
+  _cbGet["/ping"] = &_getPong;
+  _cbGet["/debug"] = &_getDebug;
+  _cbGet["/version"] = &_getVersion;
+  _cbGet["/features"] = &_getFeatures;
+  _cbGet["/audio/get_usb_id"] = & _getUsbId;
+  _cbGet["/dashboard/quote"] = &_getQuote;
+  _cbGet["/dashboard/elements"] = &_getDashboardElements;
+  _cbGet["/system/language"] = &_getLanguage;
+  _cbGet["/system/theme"] = &_getTheme;
+  _cbGet["/network/interfaces"] = &_getNetworkInterface;
+  _cbGet["/network/config"] = &_getNetworkConfig;
+  _cbGet["/library/config"] = &_getLibraryConfig;
+  _cbGet["/library/status"] = &_getLibraryStatus;
+  _cbGet["/player/remove_pulse"] = &_getPlayerRemovePulse;
+  _cbGet["/player/basic"] = &_getPlayerBasicMode;
+  _cbGet["/player/audio"] = &_getHardwareStatus;
+  _cbGet["/player/installed"] = &_getPlayersInstalled;
+  _cbGet["/player/config"] = &_getSetupConfig;
+  _cbGet["/player/status"] = &_getPlayerStatus;
+  _cbGet["/player/unmute"] = &_getPlayerUnmute;
+  _cbGet["/system/user"] = &_getSetupUser;
+  _cbGet["/system/clear_cache"] = &_getSystemClearCache;
+  _cbGet["/system/top"] = &_getSystemTop;
+  _cbGet["/system/netstat"] = &_getSystemNetstat;
+  _cbGet["/system/wizard"] = &_getWizard;
+  _cbGet["/system/license"] = &_getLicense;
+  _cbGet["/system/logs"] = &_getLogs;
+  _cbGet["/system/ramdisk"] = &_getRamdisk;
+  _cbGet["/system/running_tasks"] = &_getSystemRunningTasks;
+  _cbGet["/system/backup"] = &_getBackupSnakeoilConfig;
+  _cbGet["/snakeoil/check_version"] = &_getSnakeoilCheckVersion;
+  _cbGet["/snakeoil/check"] = &_getSnakeoilCheckDate;
+  _cbGet["/snakeoil/software"] = &_getSnakeoilSoftware;
+  _cbGet["/snakeoil/services"] = &_getSnakeoilServices;
+  _cbGet["/snakeoil/kernel"] = &_getSnakeoilKernel;
+  _cbGet["/snakeoil/hardware"] = & _getSnakeoilHardware;
+  _cbGet["/snakeoil/usb"] = &_getSnakeoilUSB;
+  _cbGet["/statistics/latest"] = &_getStatisticsLatest;
+  _cbGet["/snakeoil/stop_uhubctl"] = &_getStopUhubctl;
+
+
+  // POST
+  _cbPost["/network/config"] = &_postNetworkConfig;
+  _cbPost["/library/config"] = &_postLibraryConfig;
+  _cbPost["/library/format"] = &_postLibraryFormat;
+  _cbPost["/player/config"] = &_postSetupConfig;
+  _cbPost["/system/update"] = &_postSetupUpdate;
+  _cbPost["/system/shutdown"] = &_postSystemShutdown;
+  _cbPost["/system/upload"] = &_postSystemUpload;
+  _cbPost["/system/language"] = &_postSystemLanguage;
+  _cbPost["/system/language_edit"] = &_postSystemLanguageEdit;
+  _cbPost["/system/language_save"] = &_postSystemLanguageSave;
+  _cbPost["/system/theme"] = &_postSystemTheme;
+  _cbPost["/system/reset"] = &_postSystemReset;
+  _cbPost["/system/diagnostics"] = &_postSystemDiagnostics;
+  _cbPost["/system/tasks"] = &_postSystemTasks;
+  _cbPost["/system/cyclictest"] = &_postSystemCyclicTest;
+  _cbPost["/system/wizard"] = &_postWizard;
+  _cbPost["/system/update_ubuntu"] = &_postUpdateUbuntu;
+  // _cbPost["/system/upgrade_ubuntu"]= &_postUpgradeUbuntu;
+  //_cbPost["/system/test"] = &_postTest;
+  _cbPost["/system/kill_tasks"] = &_postSystemKillTasks;
+  _cbPost["/system/reset_password"] = &_postSystemResetPassword;
+  _cbPost["/system/restart_be"] = &_postSystemRestartBE;
+  _cbPost["/system/reset_usb"] = &_postSystemResetUSB;
+  _cbPost["/system/restore"]  = &_postSystemRestore;
+  _cbPost["/snakeoil/software"] = &_postSnakeoilSoftware;
+  _cbPost["/snakeoil/services"] = &_postSnakeoilServices;
+  _cbPost["/snakeoil/kernel"] = &_postSnakeoilKernel;
+  _cbPost["/snakeoil/hardware"] = &_postSnakeoilHardware;
+  _cbPost["/snakeoil/activation"] = &_postSnakeoilActivate;
+  _cbPost["/browse/create_folder"] = &_postBrowseCreateFolder;
+  _cbPost["/browse/add"] = &_postBrowseAddFiles;
+  _cbPost["/browse/delete"] = &_postBrowseDelFiles;
+  _cbPost["/browse/copy_to_ram"] = &_postBrowseCopyToRam;
+  _cbPost["/browse/replace_ram"] = &_postBrowseReplaceRam;
+  _cbPost["/browse/get"] = &_postFolderContents;
+  _cbPost["/player/basic"] = &_postPlayerBasicMode;
+
+  string uname;
+  OS::exec_wait("uname -a|sed -e 's/.*-dsd-\\(.*\\) #.*/\\1/g'", uname);
+
+  int tmpDate = std::atoi(uname.c_str());
+  if (tmpDate) {
+    string date1 = "2019-04-14T00:00:00";
+    string date2 = date1;
+    date2[0] = uname[0];
+    date2[1] = uname[1];
+    date2[2] = uname[2];
+    date2[3] = uname[3];
+    date2[5] = uname[4];
+    date2[6] = uname[5];
+    date2[8] = uname[6];
+    date2[9] = uname[7];
+    Time t1(date1), t2(date2);
+    _isDSDKernel = t2-t1 >= 0;
+  }
+}
+
+BackEnd::~BackEnd()
+{
+  ucout << U("Shutting down SnakeoilOS REST server") << endl;
+  _running = NULL;
+  Players::stop();
+  snakeoil::startStopCpuset(false);
+  audio::stopRavennaClient();
+  OS::unmountRamdisk();
+}
+
+void BackEnd::destroy()
+{
+  BackEnd *be = instance();
+  if (be)
+  {
+    if (be->_running) {
+      *(be->_running) = false;
+    }
+    delete be;
+    be = NULL;
+  }
+}
+
+BackEnd *BackEnd::instance()
+{
+  static BackEnd *_be = NULL;
+  if (_be == NULL)
+  {
+    _be = new BackEnd();
+  }
+  return _be;
+}
+
+void BackEnd::init(bool skipStartPlayers, const string &webroot, bool * running)
+{
+  if (_count == 0)
+  {
+    _webroot = webroot;
+    _running = running;
+
+    ++_count;
+
+    // Run tasks under it's own thread
+    auto t = pplx::create_task([this, skipStartPlayers]() -> int {
+      // Turn on mod_rewrite if it's off
+      if (!OS::exists("/etc/lighttpd/conf-enabled/10-rewrite.conf")) {
+        OS::exec_nowait("lighttpd-enable-mod rewrite; service lighttpd force-reload");
+      }
+
+      // setup network (DNS at this stage)
+      network::init();
+
+      string msg;
+      OS::fixPhpUploadLimit(512);
+
+      OS::del("/etc/systemd/system/getty.target.wants/getty@tty1.service");
+      OS::mkDir("/media/music");
+      OS::mkDir("/var/lib/alsa");
+      OS::mkDir("/media/playlists");
+      OS::mkDir("/var/www/scratch");
+      OS::exec_wait("ldconfig /usr/local/lib", msg);
+      OS::exec_nowait("chmod 777 /media/music && chmod 777 /media/playlists");
+      OS::exec_nowait("find /var/cache/lighttpd/ -type f -mtime +10 | xargs -r rm");
+      OS::exec_nowait("sed -i 's/^#!\\/bin\\/sh -e/#!\\/bin\\/bash/g' /etc/rc.local");
+      OS::exec_nowait("chown man:man /var/cache/man/ -R");
+      OS::exec_nowait("mkdir -p /var/cache/lighttpd/compress;"
+                      "chmod www-data:www-data /var/cache/lighttpd/compress");
+      // Check file permissions
+      utils::fixOwnerGroup("/var/lib/squeezeboxserver", "squeezeboxserver", "nogroup");
+
+      json::value musicCfg = _config.getMusicConfig();
+
+      // This is legacy file from old days, delete.
+      if (OS::exists("/etc/rc6.d/K99_snakeoil"))
+        OS::del("/etc/rc6.d/K99_snakeoil");
+
+      // setup apt to not replace pre-existing config file
+      if (!OS::exists("/etc/apt/apt.conf.d/90snakeoil")) {
+        OS::saveTextFile("/etc/apt/apt.conf.d/90snakeoil",
+          "Dpkg::Options {\n"
+          "  \"--force-confdef\";\n"
+          "  \"--force-confold\";\n"
+          "}\n");
+      }
+
+      // mount drives first
+      OS::mount(musicCfg, msg);
+      // mount ram drive if needed
+      OS::mountRamdisk();
+      // and start/stop all the services
+      snakeoil::startStopServices(false);
+
+      // now start the players
+      if (!skipStartPlayers)
+      {
+        string errMsg;
+        Players::init();
+        Players::start(errMsg);
+
+        // change snakeoil process priority
+        snakeoil::chprio(25);
+
+        // power off USB, putting it here as this takes a long time
+        snakeoil::powerOffUsb();
+
+        audio::startRavennaClient();
+      }
+
+/*
+      int ram = 5;
+      while (_running)
+      {
+        // check RAM
+        if ((++ram) > 5)
+        {
+          this->_stats.sample();
+          ram = 0;
+        }
+
+        // sleeps every 15 seconds
+        sleep(15);
+      }
+
+      ucout << "BackEnd Scheduler: Exit" << endl;
+*/
+      return 0;
+    });
+  }
+}
+
+int BackEnd::get(const string &api, const string &query, json::value &obj)
+{
+  return _aux(api, obj, _cbGet, query) ? status_codes::OK
+                                       : status_codes::NotFound;
+}
+
+int BackEnd::del(const string &api, json::value &obj, const string &)
+{
+  return _aux(api, obj, _cbDel) ? status_codes::OK
+                                : status_codes::NotFound;
+}
+
+int BackEnd::post(const string &api, json::value &obj, const string &data)
+{
+  if (OS::debug())
+  {
+    Json v;
+    v.append("code", 501);
+    v.append("message", "COMMON.DEBUG_MODE");
+    obj = v.value();
+    return status_codes::Created;
+  }
+
+  return _aux(api, obj, _cbPost, data) ? status_codes::Created
+                                       : status_codes::NotFound;
+}
+
+json::value _getFeaturesActivated(const string &)
+{
+  json::value v;
+
+  v["activated"] = json::value::boolean(Features::isActivated());
+
+  return v;
+}
+
+json::value _getPong(const string &)
+{
+  json::value v;
+
+  v["message"] = json::value::string(U("pong"));
+
+  return v;
+}
+
+json::value _getDebug(const string &)
+{
+  Json v;
+  v.append_bool("debug", OS::debug());
+
+  return v.value();
+}
+
+json::value _getVersion(const string &)
+{
+  Json v;
+  v.append("version", Version::getVersion());
+
+  return v.value();
+}
+
+json::value _getFeatures(const string &)
+{
+  json::value j;
+
+  Features::getFeatures(j);
+  j["wizard"] = json::value::boolean(BackEnd::instance()->config().getWizard());
+
+  return j;
+}
+
+json::value _getUsbId(const string & data)
+{
+  return audio::getUsbId(data);
+}
+
+json::value _getQuote(const string &)
+{
+  return dashboard::qotd();
+}
+
+json::value _getDashboardElements(const string &)
+{
+  return dashboard::getElements();
+}
+
+json::value _getLanguage(const string &data)
+{
+  return snakesys::getLanguage(data);
+}
+
+json::value _getTheme(const string &)
+{
+  string x;
+
+  BackEnd::instance()->config().getTheme(x);
+
+  Json theme;
+  theme.append("theme", x);
+
+  return theme.value();
+}
+
+json::value _getNetworkInterface(const string &)
+{
+  strings list;
+  network::getNICs(list);
+
+  Json net;
+
+  for (auto it = list.begin(); it != list.end(); ++it)
+  {
+    strings keys;
+    strings values;
+    network::getNIC(*it, keys, values);
+    net.addChild(*it, keys, values);
+  }
+
+  return net.value();
+}
+
+json::value _getNetworkConfig(const string &)
+{
+  Json config;
+  // common stuffs
+  config.append("hostname", network::getHostname());
+  config.append("gateway", network::getGateway());
+  config.append("dns", network::getDNS());
+
+  // network interfaces
+  strings list;
+  network::getNICs(list);
+
+  size_t i = 0;
+  Jsons items(list.size(), Json());
+  for (auto it = list.begin(); it != list.end(); ++it, ++i)
+  {
+    items[i].append("name", *it);
+    items[i].append("mode", network::getMode(*it));
+    items[i].append("ipv4", network::getIPV4(*it));
+    items[i].append("netmask", network::getIPV4Mask(*it));
+    items[i].append("mtu", network::getIPV4MTU(*it));
+  }
+
+  config.addChild("card", items);
+
+  Features::getFeatures(config);
+
+  return config.value();
+}
+
+json::value _getLibraryStatus(const string &)
+{
+  Json lib;
+  strings values;
+  library::getUninitialised(values);
+  Json format(values);
+  lib.addChild("format", format);
+  lib.append("unmounted", json::value::parse(library::getUnmounted()));
+  lib.append("mounted", json::value::parse(library::getMounted()));
+
+  return lib.value();
+}
+
+json::value _getLibraryConfig(const string &)
+{
+  Json v;
+  v.append("cred_cifs", json::value::parse(library::getCredentialsCifs()));
+  v.append("mediaItems", BackEnd::instance()->config().getMusicConfig());
+
+  Features::getFeatures(v);
+
+  return v.value();
+}
+
+json::value _getHardwareStatus(const string &)
+{
+  return audio::getStatus();
+}
+
+json::value _getPlayerRemovePulse(const string &data)
+{
+  return audio::removePulse(data);
+}
+
+json::value _getPlayersInstalled(const string &)
+{
+  return Players::getPlayers();
+}
+
+json::value _getSetupConfig(const string &)
+{
+  return Players::getConfig();
+}
+
+json::value _getPlayerStatus(const string &)
+{
+  return Players::getStatus();
+}
+
+json::value _getPlayerUnmute(const string &)
+{
+  return Players::unmute();
+}
+
+json::value _postSetupConfig(const string &data)
+{
+  return Players::setConfig(data);
+}
+
+json::value _getSetupUser(const string &)
+{
+  Json v;
+  v.append("name", snakesys::getSnakeoilUser());
+
+  return v.value();
+}
+
+json::value _postSystemShutdown(const string &)
+{
+  return snakesys::shutdown();
+}
+
+json::value _postSystemUpload(const string & data)
+{
+  return snakesys::upload(data);
+}
+
+json::value _postSystemResetPassword(const string &data)
+{
+  return snakesys::resetPassword(data);
+}
+
+json::value _postSystemTasks(const string &data)
+{
+  json::value v = json::value::parse(data);
+
+  return snakesys::getJobOutput(v["tasks"].as_integer());
+}
+
+json::value _postSystemReset(const string &)
+{
+  return snakesys::reset();
+}
+
+json::value _getSystemClearCache(const string &)
+{
+  return snakesys::clearCache();
+}
+
+json::value _postSystemDiagnostics(const string &)
+{
+  return snakesys::getSystemDiagnostics("/var/www/config/diag.tar.bz2");
+}
+
+json::value _getSystemTop(const string &)
+{
+  return snakesys::getSystemTop();
+}
+
+json::value _getSystemNetstat(const string &)
+{
+  return snakesys::getSystemNetstat();
+}
+
+json::value _getSnakeoilCheckDate(const string & data)
+{
+  return snakesys::getLastUpdateCheck();
+}
+
+json::value _getSnakeoilCheckVersion(const string &data)
+{
+  json::value obj = json::value::parse(data);
+
+  string date;
+  int code = 0;
+
+  Config &config = BackEnd::instance()->config();
+  config.getVersionCheckDate(date);
+
+  Time now;
+  Time prev(date);
+
+  if (obj.has_field("force") || date.empty() || (now - prev) > 24.0)
+  {
+    date = now.toString();
+    config.setVersionCheckDate(date);
+    code = Version::hasUpdate(obj);
+  }
+  else
+    code = 3;
+
+  Json v;
+  v.append("update", code);
+  v.append("date", date);
+
+  return v.value();
+}
+
+json::value _getSnakeoilSoftware(const string & data) {
+  return snakeoil::getSoftware(data);
+}
+
+json::value _getSnakeoilServices(const string & data) {
+  return snakeoil::getServices(data);
+}
+
+json::value _getSnakeoilKernel(const string & data) {
+  return snakeoil::getKernel(data);
+}
+
+json::value _getSnakeoilHardware(const string & data) {
+  return snakeoil::getHardware(data);
+}
+
+json::value _getSnakeoilUSB(const string &data)
+{
+  return snakeoil::getUSBPorts(data);
+}
+
+json::value _getStatisticsLatest(const string &)
+{
+  json::value v;
+  BackEnd::instance()->statistics().latest(v);
+  return v;
+}
+
+json::value _getStopUhubctl(const string &) 
+{
+  return OS::stopUhubCtl(); 
+}
+
+json::value _getWizard(const string &)
+{
+  json::value v;
+  v["wizard"] = json::value::boolean(BackEnd::instance()->config().getWizard());
+
+  return v;
+}
+
+json::value _getLicense(const string &)
+{
+  json::value v;
+
+  string license;
+  OS::readTextFile("/var/www/LICENSE", license);
+  v["message"] = json::value::string(U(license));
+  return v;
+}
+
+json::value _getLogs(const string &)
+{
+  json::value v;
+
+  string dmesg;
+  OS::exec_wait("dmesg -T", dmesg);
+  v["message"] = json::value::string(U(dmesg));
+  return v;
+}
+
+json::value _getRamdisk(const string &)
+{
+  json::value v;
+  v["mounted"] = json::value::boolean(OS::isRamdiskOK());
+
+  return v;
+}
+
+json::value _postSystemCyclicTest(const string &)
+{
+  return snakesys::runCyclicTest();
+}
+
+json::value _getSystemRunningTasks(const string &)
+{
+  return snakesys::getTasks();
+}
+
+json::value _getBackupSnakeoilConfig(const string & data)
+{
+  return snakesys::backupSnakeoilConfig(data);
+}
+
+json::value _postNetworkConfig(const string &data)
+{
+  string msg;
+
+  int code = network::setNetworkConfig(data, msg);
+
+  Json v;
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+
+json::value _postLibraryConfig(const string &data)
+{
+  strings values;
+  library::getUninitialised(values);
+
+  json::value v = library::saveConfig(data);
+  v["mounted"] = json::value::parse(library::getMounted());
+  v["unmounted"] = json::value::parse(library::getUnmounted());
+  v["format"] = json::value::array(values.size());
+  size_t c = 0;
+  for (auto it = values.begin(); it != values.end(); ++it, ++c)
+  {
+    v["format"][c] = json::value::string(U(*it));
+  }
+
+  return v;
+}
+
+json::value _postWizard(const string &data)
+{
+  json::value v = json::value::parse(data);
+  BackEnd::instance()->config().setWizard(v.has_field("wizard") &&
+                                          v["wizard"].as_bool());
+
+  return v;
+}
+
+json::value _postUpdateUbuntu(const string &data)
+{
+  Json v;
+  try {
+    json::value obj = json::value::parse(data);
+    if (obj.has_field("upgrade") && obj["upgrade"].as_bool())
+    {
+      json::value v = snakesys::update_ubuntu(data);
+      return v;
+    }
+
+  } catch (...) {} 
+  v.append("code", 1);
+  v.append("message", "Not upgrading");
+
+  return v.value();
+}
+/*
+json::value _postUpgradeUbuntu(const string & data)
+{
+  json::value obj = json::value::parse(data);
+  if (obj.has_field("upgrade") && obj["upgrade"].as_bool())
+  {
+    json::value v = snakesys::upgrade_ubuntu(data);
+    return v;
+  }
+
+  Json v;
+  v.append("code", 1);
+  v.append("message", "Not upgrading");
+
+  return v.value();
+}*/
+/*
+json::value _postTest(const string & data)
+{
+  return snakesys::test(data);
+}
+*/
+json::value _postLibraryFormat(const string &data)
+{
+  json::value d = json::value::parse(data);
+
+  Json config;
+  string message;
+  int code = library::initDisk(d["format"].as_string(), message);
+
+  strings values;
+  library::getUninitialised(values);
+  Json format(values);
+  config.addChild("format", format);
+  config.append("message", message);
+  config.append("code", code);
+  config.append("mounted", json::value::parse(library::getMounted()));
+  config.append("unmounted", json::value::parse(library::getUnmounted()));
+
+  return config.value();
+}
+
+json::value _postSetupUpdate(const string &data)
+{
+  json::value v = snakesys::update_snakeoil(data);
+
+  return v;
+}
+
+json::value _postSnakeoilActivate(const string &data)
+{
+  string msg;
+
+  json::value d = json::value::parse(data);
+  int code = snakeoil::parseActivationDetails(d["name"].as_string(),
+                                              d["mail"].as_string(),
+                                              d["code"].as_string(), msg);
+  json::value v;
+  v["message"] = json::value::string(U(msg));
+  v["code"] = json::value::number(code);
+
+  return v;
+}
+
+json::value _postSystemKillTasks(const string &data)
+{
+  json::value v = json::value::parse(data);
+
+  if (v["tasks"].size() && v["tasks"][0].is_integer())
+    snakesys::removeTask(v["tasks"][0].as_integer());
+
+  return v;
+}
+
+json::value _postSystemRestartBE(const string &)
+{
+  auto t = pplx::create_task([]() -> int {
+    ucout << U("Exiting Snakeoil RestAPI server") << endl;
+    BackEnd::instance()->destroy();
+
+    return 0;
+  });
+
+  json::value v;
+  v["code"] = json::value::number(0);
+
+  return v;
+}
+
+json::value _postSystemResetUSB(const string &)
+{
+  return OS::resetUSB();
+}
+
+json::value _postSystemRestore(const string & data)
+{
+  return snakesys::restoreSnakeoilConfig(data);
+}
+
+json::value _postSystemLanguage(const string &data)
+{
+  json::value obj = json::value::parse(data);
+
+  BackEnd::instance()->config().setLanguage(obj["language"].as_string());
+  Json v;
+  v.append("language", obj["language"].as_string());
+  return v.value();
+}
+
+json::value _postSystemLanguageEdit(const string &data)
+{
+  json::value v = json::value::parse(data);
+  return snakesys::getLanguageItems(v["language"].as_string());
+}
+
+json::value _postSystemLanguageSave(const string &data)
+{
+  BackEnd::instance()->clearLang();
+  return snakesys::setLanguageItems(data);
+}
+
+json::value _postSystemTheme(const string &data)
+{
+  json::value obj = json::value::parse(data);
+
+  BackEnd::instance()->config().setTheme(obj["theme"].as_string());
+  Json v;
+  v.append("theme", obj["theme"].as_string());
+  return v.value();
+}
+
+json::value _postSnakeoilSoftware(const string &data)
+{
+  return snakeoil::postSoftware(data);
+}
+
+json::value _postSnakeoilServices(const string & data)
+{
+  return snakeoil::postServices(data);
+}
+
+json::value _postSnakeoilKernel(const string & data)
+{
+  return snakeoil::postKernel(data);
+}
+
+json::value _postSnakeoilHardware(const string & data)
+{
+  return snakeoil::postHardware(data);
+}
+
+string BackEnd::translate(const string &key)
+{
+  try {
+    string lang;
+    config().getLanguage(lang);
+    
+    if (lang != _currentLang)
+    {
+      _currentLang = lang;
+      string contents;
+      if (!OS::readTextFile(_webroot + "assets/i18n/" + _currentLang + ".json", contents)) {
+        contents.erase(remove(contents.begin(), contents.end(), '\n'), contents.end());
+        _lang = json::value::parse(contents);
+      }
+    }
+
+    strings tokens;
+    utils::tokenise(key, tokens, '.');
+    json::value *l = &_lang;
+    size_t last = tokens.size() - 1;
+    
+    for (size_t i = 0; i < tokens.size(); ++i)
+    {
+      if (last == i)
+      {
+    
+        if ((*l).has_field(tokens[i])) {
+          return (*l)[tokens[i]].as_string();
+        }
+      }
+      else if (l->has_field(tokens[i]))
+      {
+        l = &(*l)[tokens[i]];
+      }
+    }
+  } catch (web::json::json_exception e ) {
+    cerr << "### JSON Exception: " << e.what() << endl;
+  } catch (const exception & e) {
+    cerr << "### Exception: " << e.what() << endl;
+  }
+
+  return "NoTrans:" + key;
+}
+
+json::value _postBrowseCreateFolder(const string & data)
+{
+  return Browse::createFolder(json::value::parse(data));
+}
+
+json::value _postBrowseAddFiles(const string & data) {
+  return Browse::addFiles(json::value::parse(data));
+}
+
+json::value _postBrowseDelFiles(const string & data) {
+  return Browse::delFiles(json::value::parse(data));
+}
+
+json::value _postBrowseCopyToRam(const string & data) {
+  return Browse::copyFiles(json::value::parse(data));
+}
+
+json::value _postBrowseReplaceRam(const string & data) {
+  return Browse::replaceFiles(json::value::parse(data));
+}
+
+json::value _postFolderContents(const string &data)
+{
+  json::value obj = json::value::parse(data);
+
+  return Browse::getFolderContents(obj);
+}
+
+json::value _getPlayerBasicMode(const string & data) {
+  return Players::getBasicMode();
+}
+
+json::value _postPlayerBasicMode(const string & data) {
+  return Players::setBasicMode(data);
+}
+
diff --git a/API/src/Config.cpp b/API/src/Config.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..83b7b202f4c70d958f206379fb68433c7b5b977a
--- /dev/null
+++ b/API/src/Config.cpp
@@ -0,0 +1,997 @@
+#include "Config.hpp"
+#include "stdafx.hpp"
+#include "os.hpp"
+#include "utils.hpp"
+#include "snakeoil.hpp"
+#include "players.hpp"
+#include "audio.hpp"
+#include <snakeoil/activate.h>
+
+#include <stdexcept>
+#include <sstream>
+#include <assert.h>
+
+using namespace std;
+using namespace web;
+
+#define DEFAULT_THEME "dark"
+#define LATEST_SCHEMA 5
+
+class DBWrapper
+{
+  friend Config;
+
+private:
+  DBWrapper(Config::_Data *data, sqlite3 *db, const string &stmt, string &errMsg)
+  {
+    char *zErrMsg = nullptr;
+    int rc = sqlite3_exec(db, stmt.c_str(), DBWrapper::_callback, data, &zErrMsg);
+
+    if (rc != SQLITE_OK)
+    {
+      errMsg = zErrMsg;
+      sqlite3_free(zErrMsg);
+    }
+  }
+
+  static int _callback(void *param, int argc, char **argv, char **azColName)
+  {
+    if (param)
+    {
+      Config::_Data *data = reinterpret_cast<Config::_Data *>(param);
+      data->push_back(Config::_Datum());
+
+      for (int i = 0; i < argc; ++i)
+      {
+        data->back().insert(make_pair(azColName[i], argv[i] ? argv[i] : ""));
+      }
+    }
+    return 0;
+  }
+};
+
+constexpr const char *Config::LANGUAGE;       // "language";
+constexpr const char *Config::THEME;          // "theme";
+constexpr const char *Config::LAST_CHECK;     // "last_check";
+constexpr const char *Config::REGO_NAME;      // "rego_name";
+constexpr const char *Config::REGO_MAIL;      // "rego_mail";
+constexpr const char *Config::REGO_CODE;      // "rego_code";
+constexpr const char *Config::KERNEL_OPTIONS; // "kernel_options";
+constexpr const char *Config::CLOCKSOURCE;    // "clocksource";
+constexpr const char *Config::USE_SERVER;     // "use_server";
+constexpr const char *Config::USE_CLIENT;     // "use_client";
+constexpr const char *Config::CUSTOM_AUDIO;   // "custom_audio";
+constexpr const char *Config::CUSTOM_CONFIG;
+
+constexpr const char *Config::WIZARD;
+constexpr const char *Config::NETWORK_DNS;
+constexpr const char *Config::PLAYER_SERVER;  // This is gone in schema 4
+constexpr const char *Config::PLAYER_CLIENT;  // This is gone in schema 4
+constexpr const char *Config::PLAYER_LIST;    // replacing old PLAYER_SERVER & PLAYER_CLIENT
+constexpr const char *Config::AUDIO_DEVICE;
+constexpr const char *Config::AUDIO_OPTION;
+constexpr const char *Config::UHUBCTL_ENABLE;
+constexpr const char *Config::USB_OFF;
+constexpr const char *Config::CPUSET_SHIELD;
+constexpr const char *Config::CPUSET_CONFIG;
+constexpr const char *Config::CPUSET_USER_TASKS;
+constexpr const char *Config::RAMDISK;
+constexpr const char *Config::RAMDISK_ENABLE;
+constexpr const char *Config::RAMDISK_FREE;
+constexpr const char *Config::RAMDISK_SIZE;
+constexpr const char *Config::RAMDISK_TYPE;
+
+Config::Config()
+    : _db(nullptr)
+{
+  OS::mkDir("/var/www/config");
+  _getDb();
+}
+
+Config::~Config()
+{
+  if (_db != nullptr)
+    sqlite3_close(_db);
+}
+
+void Config::_getDb()
+{
+  //char *zErrMsg = 0;
+  int rc;
+
+  rc = sqlite3_open("/var/www/config/snakeoil.db", &_db);
+
+  if (rc)
+    throw runtime_error(string("Cannot open Snakeoil Database:") + sqlite3_errmsg(_db));
+
+  if (!sqlite3_threadsafe())
+    throw runtime_error("sqlite3 is not thread safe!");
+
+  // check if it's new
+  string msg;
+  _Data data;
+
+  if (_execSQL("SELECT VERSION FROM schema;", msg, &data))
+  {
+    if (data.empty())
+    {
+      // blank database. set to latest schema
+      _newDb();
+    }
+    else
+    {
+      // existing database, check version to see if need to upgrade.
+      // Remember to update LATEST_SCHEMA macro every time you add a change!!
+      int version = atoi(data.back().begin()->second.c_str());
+
+      for (int current = version + 1; current <= LATEST_SCHEMA; ++current)
+      {
+        _setSchema(current);
+      }
+    }
+    // Check MAC address entries
+    string mac;
+    getMacAddress(1, mac);
+    if (mac == "_MIPV4=\"\"") {
+      string tmp, msg;
+      utils::getMacAddress(tmp, 10);
+      _execSQL("DELETE from machine_address; REPLACE INTO machine_address(IPV4) values " + tmp + ';', msg);
+    }
+  }
+  else
+  {
+    _newDb();
+  }
+}
+
+void Config::_newDb()
+{
+  string msg;
+  _execSQL("CREATE TABLE schema(VERSION INT);", msg);
+  _execSQL("CREATE TABLE settings("
+           "KEY TEXT PRIMARY KEY NOT NULL, "
+           "VALUE TEXT);",
+           msg);
+  _execSQL("CREATE TABLE media("
+           "MEDIA TEXT PRIMARY KEY NOT NULL, "
+           "MOUNT TEXT, "
+           "OPTIONS TEXT, "
+           "TYPE TEXT NOT NULL);",
+           msg);
+  _execSQL("CREATE TABLE machine_address("
+           "IPV4 TEXT PRIMARY KEY NOT NULL);",
+           msg);
+  
+  _execSQL("CREATE TABLE priority("
+           "NAME TEXT NOT NULL, "
+           "PRIORITY INT NOT NULL);",
+           msg);
+  _execSQL("CREATE TABLE player_config("
+           "PLAYER TEXT PRIMARY KEY NOT NULL,"
+           "CONFIG TEXT NOT NULL)",
+           msg);
+
+  _execSQL("INSERT INTO schema (VERSION) values (5);", msg);
+  
+  
+  setLanguage("en");
+  setTheme(DEFAULT_THEME);
+  setServiceSSH(true);
+  setServiceConsole(true);
+  setServiceSamba(true);
+  setPlayerBasicMode(true);
+  setWizard(true);
+}
+
+void Config::_setSchema(int version)
+{
+  string msg;
+
+  // update database schema
+  switch (version)
+  {
+    case 1:
+    {
+      cout << "_setSchema(1)" << endl;
+      setServiceAvaHi(true);
+      _execSQL("UPDATE schema set VERSION=1;", msg);
+    
+      string list;
+      getMacAddress(1, list);
+      if (list == "_MIPV4=\"24:4f:4f:24:90:81\"")
+      {
+        string tmp;
+        utils::getMacAddress(tmp, 10);
+        _execSQL("DELETE from machine_address; REPLACE INTO machine_address(IPV4) values " + tmp + ';', msg);
+      }
+      break;
+    }
+    case 2:
+    {
+      cout << "_setSchema(2)" << endl;
+      _execSQL("UPDATE schema set VERSION=2;", msg);
+      _execSQL("CREATE TABLE player_options("
+               "PLAYER TEXT NOT NULL, "
+               "OUTPUT NOT NULL, "
+               "PARAMS TEXT, PRIMARY KEY (PLAYER, OUTPUT));",
+               msg);
+    }
+    case 3:
+    {
+      string u;
+      getUsbOff(u);
+      setUHubCtlEnabled(!u.empty());  
+      _execSQL("UPDATE schema set VERSION=3;", msg);
+    }
+    case 4:
+    {
+      _execSQL("CREATE TABLE IF NOT EXISTS player_config("
+               "PLAYER TEXT PRIMARY KEY NOT NULL,"
+               "CONFIG TEXT NOT NULL);",
+               msg);
+
+      // Change the way music players work
+      string server, client;
+      SetupConfig serverConfig, clientConfig;
+
+      _get(PLAYER_SERVER, server);
+      _get(PLAYER_CLIENT, client); 
+      const bool useClient = _get(USE_CLIENT);
+      const bool useServer = _get(USE_SERVER);
+      bool hasClient; 
+
+
+      // _execSQL("CREATE TABLE player_config", msg);
+      cout << "useClient: " << useClient << endl
+           << "useServer: " << useServer << endl
+           << "   Server: " << server << endl
+           << "   Client: " << client << endl;
+
+      strings list;
+
+      if (useServer) {
+        Players::getSetupConfig(server, serverConfig);
+        hasClient = serverConfig.has_client;
+        cout << "Migrating server: " << serverConfig.path << endl
+             << "          Custom: " << serverConfig.custom_audio << endl
+             << "       hasClient: " << hasClient << endl
+             << "          config: " << serverConfig.config << endl;
+
+        json::value config = _getPlayerAudioDevices();
+        if (serverConfig.custom_audio) {
+          string customConfig;
+          _getCustomConfig(customConfig); 
+          config[0]["custom"] = json::value::boolean(true);
+          config[0]["custom_config"] = json::value::string(U(customConfig));
+        }
+
+        setPlayerRuntimeConfig(serverConfig.path, config); 
+
+        list.push_back(serverConfig.path);
+      }
+
+      if ((useServer && hasClient && useClient) || (!useServer && useClient)) {
+        Players::getSetupConfig(client, clientConfig);
+        cout << "Migrating client: " << clientConfig.path  << endl;
+        if (clientConfig.alsa_setup) {
+          json::value config = _getPlayerAudioDevices();
+
+          setPlayerRuntimeConfig(clientConfig.path, config); 
+        }
+        list.push_back(clientConfig.path);
+      }
+
+      // convert strings into an array object. Do a utils function next?
+      json::value players = json::value::array(list.size()); 
+      for (auto pos = 0; pos < list.size(); ++pos) {
+        players[pos] = json::value::string(U(list[pos]));
+      }
+
+      setPlayersToStart(players);
+
+      _execSQL("UPDATE schema set VERSION=4;", msg);
+      break;
+    }
+    case 5:
+    {
+      setPlayerBasicMode(false);
+      _execSQL("UPDATE schema set VERSION=5;", msg);
+      break;
+    }
+    case 6:
+    {
+      // Drop these tables and entries from 4.
+      // _execSQL("DROP TABLE IF EXISTS audio_devices", msg);
+      // _execSQL("DELETE FROM settings where key=''", msg);
+
+      // _execSQL("DELETE FROM settings where key='player_server'", msg);
+      // _execSQL("DELETE FROM settings where key='player_client'", msg);
+      // _execSQL("DELETE FROM settings where key='use_server'", msg);
+      // _execSQL("DELETE FROM settings where key='use_client'", msg);
+      // _execSQL("DELETE FROM settings where key='use_custom'", msg);
+      // _execSQL("DELETE FROM settings where key='custom_config'", msg);
+      // _execSQL("UPDATE schema set VERSION=6;", msg);
+      break;
+    }
+  }
+}
+
+bool Config::_execSQL(const string &stmt, string &errMsg, Config::_Data *data)
+{
+  DBWrapper dbw(data, _db, stmt, errMsg);
+  return errMsg.empty();
+}
+
+bool Config::_get(const string &key)
+{
+  string x;
+  _get(key, x);
+
+  return x == "true";
+}
+
+bool Config::_get(const string &key, json::value & value)
+{
+  string t;
+  const bool code = _get(key, t);
+  if (!t.empty()) {
+    value = json::value::parse(t);
+  }
+  return code;
+}
+
+bool Config::_get(const string &key, string &value)
+{
+  string msg;
+  _Data data;
+  if (_execSQL("SELECT value FROM settings WHERE key='" + key + "';", msg, &data))
+  {
+    auto it = data.begin();
+    if (it != data.end())
+    {
+      value = it->begin()->second;
+      return true;
+    }
+  }
+  value.clear();
+  return false;
+}
+
+bool Config::_set(const string &key, const json::value & value)
+{
+  return _set(key, value.serialize());
+}
+
+bool Config::_set(const string &key, const string &value)
+{
+  if (key.empty())
+    throw runtime_error("Config:: key is blank");
+  string msg;
+  return _execSQL("INSERT OR REPLACE INTO settings(KEY,VALUE) values('" + key + "', '" + value + "');", msg);
+}
+
+bool Config::_set(const string &key, bool value)
+{
+  if (key.empty())
+    throw runtime_error("Config:: key is blank");
+  string msg;
+
+  return _execSQL("INSERT OR REPLACE INTO settings(KEY,VALUE) values('" + key + "', '" + (value ? "true" : "false") + "');", msg);
+}
+
+bool Config::isActivated()
+{
+  string name, mail, code;
+
+  getRegoName(name);
+  getRegoMail(mail);
+  getRegoCode(code);
+  Snakeoil::Activate a(name, mail, code);
+
+  return a.isActivated();
+}
+
+bool Config::getLanguage(std::string &x) { return _get(LANGUAGE, x); }
+bool Config::setLanguage(const std::string &x) { return _set(LANGUAGE, x); }
+
+bool Config::getUsbOff(std::string &x) { return _get(USB_OFF, x); }
+bool Config::setUsbOff(const std::string &x) { return _set(USB_OFF, x); }
+
+bool Config::getUHubCtlEnabled()
+{
+  return _get(UHUBCTL_ENABLE);
+}
+
+bool Config::setUHubCtlEnabled(bool v)
+{
+  return _set(UHUBCTL_ENABLE, v);
+}
+
+bool Config::getTheme(std::string &x)
+{
+  bool c = _get(THEME, x);
+  if (x.empty())
+  {
+    x = DEFAULT_THEME;
+    setTheme(x);
+  }
+  return c;
+}
+
+bool Config::setTheme(const std::string &x) { return _set(THEME, x); }
+
+bool Config::getRegoName(std::string &x) { return _get(REGO_NAME, x); }
+bool Config::setRegoName(const std::string &x) { return _set(REGO_NAME, x); }
+
+bool Config::getRegoMail(std::string &x) { return _get(REGO_MAIL, x); }
+bool Config::setRegoMail(const std::string &x) { return _set(REGO_MAIL, x); }
+
+bool Config::getRegoCode(std::string &x) { return _get(REGO_CODE, x); }
+bool Config::setRegoCode(const std::string &x) { return _set(REGO_CODE, x); }
+
+bool Config::getVersionCheckDate(std::string &x) { return _get(LAST_CHECK, x); }
+bool Config::setVersionCheckDate(const std::string &x) { return _set(LAST_CHECK, x); }
+
+/*
+bool Config::getUseServer()
+{
+  return _get(USE_SERVER);
+}
+
+bool Config::setUseServer(bool x)
+{
+  return _set(USE_SERVER, x);
+}
+
+bool Config::setUseClient(bool x)
+{
+  return _set(USE_CLIENT, x);
+}
+
+bool Config::getUseClient()
+{
+  return _get(USE_CLIENT);
+}
+*/
+
+bool Config::_getCustomConfig(string &x)
+{
+  return _get(CUSTOM_CONFIG, x);
+}
+
+bool Config::_setCustomConfig(const string &x)
+{
+  return _set(CUSTOM_CONFIG, x);
+}
+
+bool Config::getNetDNS(std::string &x)
+{
+  return _get(NETWORK_DNS, x);
+}
+
+bool Config::setNetDNS(const std::string &x)
+{
+  return _set(NETWORK_DNS, x);
+}
+
+bool Config::getWizard()
+{
+  return _get(WIZARD);
+}
+
+bool Config::setWizard(bool x)
+{
+  return _set(WIZARD, x);
+}
+
+bool Config::getServiceSSH()
+{
+  return _get(USE_SSH);
+}
+
+bool Config::setServiceSSH(bool x)
+{
+  return _set(USE_SSH, x);
+}
+
+bool Config::getServiceConsole()
+{
+  return _get(USE_CONSOLE);
+}
+
+bool Config::setServiceConsole(bool x)
+{
+  return _set(USE_CONSOLE, x);
+}
+
+bool Config::getServiceSamba()
+{
+  return _get(USE_SAMBA);
+}
+
+bool Config::setServiceSamba(bool x)
+{
+  return _set(USE_SAMBA, x);
+}
+
+bool Config::getServiceStorageMonitor()
+{
+  return _get(USE_STORE_MON);
+}
+
+bool Config::setServiceStorageMonitor(bool x)
+{
+  return _set(USE_STORE_MON, x);
+}
+
+bool Config::getServiceAvaHi()
+{
+  return _get(USE_AVAHI);
+}
+
+bool Config::setServiceAvaHi(bool x)
+{
+  return _set(USE_AVAHI, x);
+}
+
+bool Config::_getPlayerServer(std::string &x)
+{
+  _get(PLAYER_SERVER, x);
+
+  // no more mpd-git, use mpd-v20 instead
+  if (x == "mpd-git")
+    x = "mpd-v21";
+
+  if (!x.empty())
+  {
+    json::value v = Players::getPlayers()["server"];
+    bool not_found = true;
+    for (size_t i = 0; i < v.size(); ++i)
+    {
+      if (v[i]["path"].as_string() == x)
+        not_found = false;
+    }
+    if (not_found)
+    {
+      x.clear();
+
+      _setPlayerServer(x);
+    }
+  }
+
+  return !x.empty();
+}
+
+bool Config::_setPlayerServer(const std::string &x) { return _set(PLAYER_SERVER, x); }
+
+bool Config::_getPlayerClient(std::string &x)
+{
+  _get(PLAYER_CLIENT, x);
+  if (!x.empty())
+  {
+    json::value v = Players::getPlayers()["client"];
+    bool not_found = true;
+
+    for (size_t i = 0; i < v.size(); ++i)
+    {
+      if (v[i]["path"].as_string() == x)
+        not_found = false;
+    }
+    if (not_found)
+    {
+      x.clear();
+
+      _setPlayerClient(x);
+    }
+  }
+
+  return !x.empty();
+}
+
+bool Config::_setPlayerClient(const std::string &x)
+{
+  return _set(PLAYER_CLIENT, x);
+}
+
+json::value Config::_getPlayerAudioDevices()
+{
+  string msg;
+  _Data data;
+  json::value d;
+
+  if (_execSQL("SELECT * FROM audio_device;", msg, &data))
+  {
+    d = json::value::array(data.size());
+    size_t c = 0;
+    for (auto it = data.begin(); it != data.end(); ++it, ++c)
+    {
+      auto data2 = *it;
+      d[c]["output"] = json::value::string(U(data2["OUTPUT"]));
+      d[c]["name"] = json::value::string(U(data2["NAME"]));
+      d[c]["options"] = json::value::string(U(data2["OPTIONS"]));
+      d[c]["format"] = json::value::string(U(data2["FORMAT"]));
+      d[c]["custom"] = json::value::boolean(false);
+      d[c]["custom_config"] = json::value::string(U(""));
+    }
+  }
+
+  return d;
+}
+
+bool Config::setMusicConfig(const string &data, string &errMsg)
+{
+  json::value d = json::value::parse(data);
+  _execSQL("DELETE FROM media;", errMsg);
+
+  ostringstream o;
+  for (size_t i = 0; i < d["mediaItems"].size(); ++i)
+  {
+    json::value &obj = d["mediaItems"][i];
+
+    o << "INSERT INTO media (MEDIA, MOUNT, OPTIONS, TYPE) VALUES "
+         "("
+      << obj["media"] << ','
+      << obj["mount"] << ','
+      << obj["options"] << ','
+      << obj["type"] << ");";
+  }
+
+  return !_execSQL(o.str(), errMsg);
+}
+
+json::value Config::getMusicConfig()
+{
+  string msg;
+  _Data data;
+  json::value d;
+
+  if (_execSQL("SELECT * FROM media;", msg, &data))
+  {
+    d = json::value::array(data.size());
+    size_t c = 0;
+    for (auto it = data.begin(); it != data.end(); ++it, ++c)
+    {
+      d[c]["media"] = json::value::string(U((*it)["MEDIA"]));
+      d[c]["mount"] = json::value::string(U((*it)["MOUNT"]));
+      d[c]["type"] = json::value::string(U((*it)["TYPE"]));
+      d[c]["options"] = json::value::string(U((*it)["OPTIONS"]));
+    }
+  }
+
+  return d;
+}
+
+bool Config::getClockSource(std::string &x)
+{
+  bool t = _get(CLOCKSOURCE, x);
+
+  if (x.empty())
+  {
+    OS::readTextFile("/sys/devices/system/clocksource/clocksource0/current_clocksource", x);
+    utils::trim(x);
+  }
+  return t;
+}
+
+bool Config::setClockSource(const std::string &x)
+{
+  return _set(CLOCKSOURCE, x);
+}
+
+bool Config::getKernelOptions(std::string &x)
+{
+  return _get(KERNEL_OPTIONS, x);
+}
+
+bool Config::setKernelOptions(const std::string &x)
+{
+  return _set(KERNEL_OPTIONS, x);
+}
+
+void Config::getMacAddress(size_t size, std::string &env)
+{
+  env += "_MIPV4=\"";
+  string msg;
+  _Data data;
+  if (_execSQL("SELECT * FROM machine_address;", msg, &data))
+  {
+    size_t c = 0;
+    for (auto it = data.begin(); it != data.end() && c < size; ++it, ++c)
+    {
+      if (c)
+        env += '~';
+      env += ((*it)["IPV4"]);
+    }
+  }
+  env += "\"";
+}
+
+bool Config::setProcPrio(web::json::value n)
+{
+  bool diff = false;
+  json::value o = getProcPrio();
+  bool equal = o.size() == n.size();
+
+  string msg;
+  if (n.size() > 0 && equal)
+  {
+    for (size_t i = 0; !diff && i < o.size(); ++i)
+    {
+      diff |= (n[i]["name"].as_string() != o[i]["name"].as_string() ||
+               n[i]["priority"].as_string() != o[i]["priority"].as_string());
+    }
+  }
+
+  if (diff || !equal)
+  {
+    _execSQL("DELETE FROM priority;", msg);
+    ostringstream ostr;
+    ostr << "INSERT INTO priority (NAME, PRIORITY) VALUES ";
+    for (size_t i = 0; i < n.size(); ++i)
+    {
+      if (i)
+        ostr << ',';
+
+      ostr << "(\"" << n[i]["name"].as_string() << "\","
+           << n[i]["priority"].as_string() << ')';
+    }
+    ostr << ';';
+    _execSQL(ostr.str(), msg);
+  }
+
+  return diff || !equal;
+}
+
+bool Config::setCpuConfig(web::json::value value)
+{
+  bool v = false;
+  bool b = value[CPUSET_SHIELD].as_bool();
+
+  // check if CPU Shielding option has changed.
+  if ((v |= _get(CPUSET_SHIELD) != b))
+  {
+    _set(CPUSET_SHIELD, b);
+  }
+
+  // save CPU sheilding parameters regardless
+  {
+    string x, y;
+    _get(CPUSET_CONFIG, x);
+    for (uint i = 0; i < value[CPUSET_CONFIG].size(); ++i)
+    {
+      y += value[CPUSET_CONFIG][i]["user"].as_bool() ? '1' : '0';
+    }
+
+    if (x != y)
+    {
+      v = true;
+      _set(CPUSET_CONFIG, y);
+    }
+  }
+  return v;
+}
+
+json::value Config::getCpuConfig()
+{
+  json::value v;
+  string tmp, tmp2;
+
+  _get(CPUSET_CONFIG, tmp2);
+  OS::exec_wait("cat /proc/cpuinfo |grep ^processor|wc -l", tmp);
+  size_t num = static_cast<size_t>(atoi(tmp.c_str()));
+  string tasks;
+  if (OS::exists("/sys/fs/cgroup/cpuset/user/tasks"))
+  {
+    OS::exec_wait("cat /sys/fs/cgroup/cpuset/user/tasks|tr '\\n' ' '", tasks);
+  }
+  v[CPUSET_USER_TASKS] = json::value::string(U(tasks));
+
+  // -------
+  json::value &cpuSys = v[CPUSET_CONFIG] = json::value::array(num);
+
+  if (tmp2.length() != num)
+  {
+    // Initial setup. Half the CPU will go to system, half to user
+    for (size_t i = 0; i < num; ++i)
+    {
+      // cset shield --cpu 1-7,9-15 --kthread=on
+      cpuSys[i]["core"] = json::value::number(i);
+      cpuSys[i]["user"] = json::value::boolean(((i + 1) / 2) ? true : false);
+    }
+  }
+  else
+  {
+    for (size_t i = 0; i < tmp2.length(); ++i)
+    {
+      cpuSys[i]["core"] = json::value::number(i);
+      cpuSys[i]["user"] = json::value::boolean(tmp2[i] == '1');
+    }
+  }
+
+  v[CPUSET_SHIELD] = json::value::boolean(_get(CPUSET_SHIELD));
+
+  return v;
+}
+
+bool Config::setRamdiskConfig(web::json::value value) {
+  bool v1 = false,
+       v2 = false,
+       v3 = false;
+  string size, type, s_size, s_type;
+  bool enabled = value[RAMDISK_ENABLE].as_bool();
+  if (enabled) {
+    if (value[RAMDISK_SIZE].is_number())
+    {
+      ostringstream o;
+      o << value[RAMDISK_SIZE].as_integer();
+      size = o.str(); 
+    }
+    else
+      size = value[RAMDISK_SIZE].as_string();
+    type = value[RAMDISK_TYPE].as_string();
+  }
+  s_type = getRamdiskType();
+  s_size = getRamdiskSize();
+
+  if (getRamdiskEnable() != enabled)
+  {
+    v1 = true; setRamdiskEnable(enabled);
+  }
+
+  if (s_size != size) 
+  {
+    v2 = true; _set(RAMDISK_SIZE, size);
+  }
+
+  if (s_type != type) 
+  {
+    v3 = true; _set(RAMDISK_TYPE, type);
+  }
+
+  bool changed = v1|v2|v3;
+  if (changed) {
+    if (enabled) 
+      OS::mountRamdisk();
+    else
+      OS::unmountRamdisk();
+  }
+
+  return changed;
+}
+
+json::value Config::getRamdiskConfig()
+{
+  json::value v;
+  string s_size, s_type;
+
+  _get(RAMDISK_SIZE, s_size);
+  _get(RAMDISK_TYPE, s_type);
+  if(s_type.empty()) s_type = "tmpfs";
+
+  v[RAMDISK_ENABLE] = json::value::boolean(_get(RAMDISK_ENABLE));
+  v[RAMDISK_TYPE  ] = json::value::string(s_type);
+  v[RAMDISK_FREE  ] = json::value::number(OS::getFreeRAM());
+  v[RAMDISK_SIZE  ] = json::value::number(atoi(s_size.c_str()));
+
+  return v;
+}
+
+json::value Config::getProcPrio()
+{
+  json::value v;
+  string msg;
+  _Data data;
+
+  if (_execSQL("SELECT * FROM priority;", msg, &data))
+  {
+    v = json::value::array(data.size());
+    size_t c = 0;
+    for (auto it = data.begin(); it != data.end(); ++it, ++c)
+    {
+      v[c]["index"] = json::value::number(c);
+      v[c]["name"] = json::value::string(U((*it)["NAME"]));
+      v[c]["priority"] = json::value::string(U((*it)["PRIORITY"]));
+    }
+  }
+
+  return v;
+}
+
+bool Config::getRamdiskEnable()
+{
+  return _get(RAMDISK_ENABLE);
+}
+
+
+bool Config::setRamdiskEnable(bool enabled)
+{
+  return _set(RAMDISK_ENABLE, enabled);
+}
+
+string Config::getRamdiskSize()
+{
+  string sz;
+  _get(RAMDISK_SIZE, sz);
+
+  return sz;
+}
+
+string Config::getRamdiskType()
+{
+  string t;
+  _get(RAMDISK_TYPE, t);
+
+  return t;
+}
+
+bool Config::setPlayerRuntimeConfig(const string & playerName, const web::json::value & config) {
+  string msg;
+  return _execSQL("INSERT OR REPLACE INTO player_config (player, config) VALUES ('" + 
+                    playerName + "', '" + config.serialize() + "');", msg);
+}
+
+bool Config::setAllPlayersRuntimeConfig(const web::json::value & allConfig) {
+  const json::object & obj = allConfig.as_object();
+
+  bool code = true;
+
+  for (auto it = obj.cbegin(); it != obj.cend(); ++it) {
+    code &= setPlayerRuntimeConfig(it->first, it->second);
+  }
+
+  return code;
+}
+
+bool Config::getPlayerRuntimeConfig(const string & playerName, json::value & config)
+{
+  string msg;
+  _Data data;
+  int code = _execSQL("SELECT * FROM player_config where PLAYER='" + playerName + "';", msg, &data);
+  if (!data.empty()) {
+    _Datum & d = data.back();
+    try {
+      config = json::value::parse(d["CONFIG"]);
+    } catch (const exception & e) {
+      cout << e.what() << endl;
+      code = 1;
+    }
+  }
+
+  return code;
+}
+
+bool Config::getAllPlayersRuntimeConfig(web::json::value & allConfig) {
+  string msg;
+  _Data data;
+
+  int code = _execSQL("SELECT * FROM player_config;", msg, &data);
+  if (code) 
+  {
+    for (auto it = data.begin(); it != data.end(); ++it)
+    {
+      auto data2 = *it;
+      allConfig[U(data2["PLAYER"])] = json::value::parse(U(data2["CONFIG"]));
+    }
+  }
+
+  return code;
+}
+
+bool Config::setPlayersToStart(const json::value & players) {
+  // cout << "Config::setPlayersToStart => " << players << endl;
+  return _set(PLAYER_LIST, players);
+}
+
+bool Config::getPlayersToStart(json::value & players)
+{
+  return _get(PLAYER_LIST, players);
+}
+
+bool Config::getPlayerBasicMode() {
+  return _get(PLAYER_BASIC_MODE);
+}
+
+bool Config::setPlayerBasicMode(bool basic) {
+  return _set(PLAYER_BASIC_MODE, basic);
+}
+
diff --git a/API/src/Json.cpp b/API/src/Json.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3063b5c837c067baaf462fdb1ea9e6ff8c5b3a21
--- /dev/null
+++ b/API/src/Json.cpp
@@ -0,0 +1,96 @@
+#include "Json.hpp"
+
+using namespace std;
+using namespace web;
+
+Json::Json()
+    : _json(json::value::object())
+{
+}
+
+Json::Json(const strings &keys, const strings &values)
+    : _json(json::value::array(keys.size()))
+{
+  size_t i = 0;
+  for (auto kIt = keys.begin(), vIt = values.begin(); kIt != keys.end() && vIt != values.end(); ++kIt, ++vIt)
+  {
+    _json[i]["key"] = json::value::string(U(*kIt));
+    _json[i]["value"] = json::value::string(U(*vIt));
+    ++i;
+  }
+}
+
+Json::Json(const strings &values)
+    : _json(json::value::array(values.size()))
+{
+  size_t i = 0;
+  for (auto it = values.begin(); it != values.end(); ++it)
+    _json[i++] = json::value::string(U(*it));
+}
+
+void Json::append(const string &key, const string &value)
+{
+  _json[key] = json::value::string(U(value));
+}
+
+void Json::append(const string &key, int value)
+{
+  _json[key] = json::value::number(value);
+}
+
+void Json::append_bool(const string &key, bool value)
+{
+  _json[key] = json::value::boolean(value);
+}
+
+void Json::append(const string &key, json::value v)
+{
+  _json[key] = v;
+}
+
+void Json::append(const std::string &key, std::vector<int> &jobs)
+{
+  json::value &v = _json[key];
+  v.array(jobs.size());
+  size_t c = 0;
+  for (auto it = jobs.begin(); it != jobs.end(); ++it)
+    v[c++] = json::value::number(*it);
+}
+
+void Json::addChild(const string &childName, Json &list)
+{
+  _json[childName] = list.value();
+}
+
+void Json::addChild(const string &childName, Jsons &list)
+{
+  json::value &i = _json[childName] = json::value::array(list.size());
+
+  size_t j = 0;
+
+  for (auto it = list.begin(); it != list.end(); ++it, ++j)
+    i[j] = it->value();
+}
+
+void Json::addChild(const string &childName, const strings &keys, const strings &values)
+{
+  size_t elems = keys.size();
+
+  json::value &obj = _json[childName] = json::value::array(elems);
+  size_t i = 0;
+  for (auto kIt = keys.begin(), vIt = values.begin(); kIt != keys.end() && vIt != values.end(); ++kIt, ++vIt)
+  {
+    obj[i]["key"] = json::value::string(U(*kIt));
+    obj[i]["value"] = json::value::string(U(*vIt));
+    ++i;
+  }
+}
+
+void Json::addChild(const std::string &childName, web::json::value obj){
+  _json[childName] = obj;
+}
+
+json::value &Json::value()
+{
+  return _json;
+}
diff --git a/API/src/Quotes.cpp b/API/src/Quotes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a48d3cf34fa26c8eb36f476eec6b399215421e57
--- /dev/null
+++ b/API/src/Quotes.cpp
@@ -0,0 +1,78 @@
+#include "Quotes.hpp"
+
+using namespace std;
+
+Quotes::Quotes()
+    : _quotes({Quote("Audiophiles don't use their equipment to listen to your music. Audiophiles use your music to listen to their equipment.", "Alan Parsons"),
+               Quote("Because Music Matters.", "Marantz"),
+               Quote("What is wanted is not the will to believe, but the will to find out, which is the exact opposite.",
+                     "Bertrand Russell, _Sceptical_Essays_, 1928"),
+               Quote("'double-blind comparative listening tests' as the last refuge of the agenda-driven scoundrel.",
+                     "John Atkinson", "http://www.stereophile.com/content/listening-143"),
+               Quote("Shut up and take my money!", "Phillip J. Fry (Futurama)"),
+               Quote("No Fair! You changed the outcome by measuring it!", "Hubert J. Farnsworth (Futurama)"),
+               Quote("It doesn't sound like live music: it sounds better. Clearer, more pure. ",
+                     "Alexis Petridis", "http://www.esquire.co.uk/culture/music/8618/are-the-audiophiles-hearing-something-were-not/"),
+               Quote("The weirdest thing is that the music doesn't appear to be coming out of the speakers: it seems to be happening in a space just in front of you.",
+                     "Alexis Petridis", "http://www.esquire.co.uk/culture/music/8618/are-the-audiophiles-hearing-something-were-not/"),
+               Quote("It feels like it's in 3D: you could walk around it, you could reach out and touch it. It's astonishing.",
+                     "Alexis Petridis", "http://www.esquire.co.uk/culture/music/8618/are-the-audiophiles-hearing-something-were-not/"),
+               Quote("Just because a test is blind does not make it \"scientific.\" Those who insist that it is are the zealots, sir.",
+                     "John Atkinson", "http://www.stereophile.com/comment/543658#comment-543658"),
+               Quote("Well, I reject your reality and substitute my own!", "Paul Bradford (The Dungeonmaster)"),
+               Quote("... that the demands for blind tests are very often made by those who have no experience of such tests. Such people thus have no idea of how difficult it is to design and perform a valid test that produces meaningful results.",
+                     "John Atkinson", "http://www.stereophile.com/content/simple-everything-appears-simple"),
+               Quote("I would like 2016 to be the year when people remembered that science is a method of investigation,and NOT a belief system.",
+                     "John Cleese", "https://twitter.com/JohnCleese/status/683681888687538177"),
+               Quote("Nobody ever got fired for buying Accuphase!", "Doncentric"),
+               Quote("Be open to new ideas, to different ideas, even if they look \"strange\" at first sight.",
+                     "Juergen Reis", "http://www.audiostream.com/content/open-and-tolerant-mbls-juergen-reis-listening-measurements-and-uncertainty"),
+               Quote("Not everything that can be counted counts, and not everything that counts can be counted.",
+                     "William Bruce Cameron, Informal Sociology: A Casual Introduction to Sociological Thinking (1963)"),
+               Quote("Use your ears. They're the best test instrument the world has ever known. Your system is for your own enjoyment; why look to others for information about how good it is when you can simply hear it for yourself?",
+                     "Roger Skof", "http://audiophilereview.com/preamps/what-do-audio-specs-really-mean.html"),
+               Quote("Good, better, best. Never let it rest. Until your good is better and your better is best.",
+                     "Tim Duncan (NBA Future Hall Of Famer)"),
+               Quote("Dear Music,<br />Thanks for always clearing my head, healing my heart, and lifting my spirits.", "Lori Deschene"),
+               Quote("One good thing about music, when it hits you, you feel no pain.", "Bob Marley"),
+               Quote("What is important to the eye is not necessarily important to the ear. Why should it be? Nature makes sure each does its job and does its job perfectly. You get cues from the eye, but some things that look gross in the frequency response, the ear says, \"I don't care\".", "Siegfried Linkwitz")}),
+      _it(_quotes.end())
+{
+}
+
+Quotes::~Quotes()
+{
+}
+const string &Quotes::getQuote()
+{
+      if (_it == _quotes.end())
+      {
+            // re-shuffle the quotes
+            std::srand(unsigned(std::time(0)));
+            std::random_shuffle(_quotes.begin(), _quotes.end());
+            _it = _quotes.begin();
+      }
+      else
+      {
+            ++_it;
+            if (_it == _quotes.end())
+            {
+                  // re-shuffle the quotes
+                  std::srand(unsigned(std::time(0)));
+                  std::random_shuffle(_quotes.begin(), _quotes.end());
+                  _it = _quotes.begin();
+            }
+      }
+
+      return _it->quote;
+}
+
+const string &Quotes::getAuthor() const
+{
+      return _it->author;
+}
+
+const string &Quotes::getURL() const
+{
+      return _it->url;
+}
diff --git a/API/src/Remote.cpp b/API/src/Remote.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..50e4b2b9ab685ad7c5fa8e4aa601f362c3dbb1e5
--- /dev/null
+++ b/API/src/Remote.cpp
@@ -0,0 +1,8 @@
+#include "Remote.hpp"
+
+#include "RemoteLMS.hpp"
+
+RemoteInterface *Remote::getRemote()
+{
+  return new RemoteLMS();
+}
diff --git a/API/src/RemoteInterface.cpp b/API/src/RemoteInterface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..93401f879d934dbfb9c6d629ce0eb31e49f128b9
--- /dev/null
+++ b/API/src/RemoteInterface.cpp
@@ -0,0 +1,5 @@
+#include "RemoteInterface.hpp"
+
+RemoteInterface::RemoteInterface() {}
+
+RemoteInterface::~RemoteInterface() {}
diff --git a/API/src/RemoteLMS.cpp b/API/src/RemoteLMS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7973196ebfdd077acd7daa7c6b4acb73f182bead
--- /dev/null
+++ b/API/src/RemoteLMS.cpp
@@ -0,0 +1,12 @@
+#include "RemoteLMS.hpp"
+
+using namespace std;
+
+RemoteLMS::RemoteLMS()
+    : RemoteInterface()
+{
+}
+
+void RemoteLMS::getFolder(const string & /*path */, FileItems & /*fileItems */)
+{
+}
diff --git a/API/src/RestWrapper.cpp b/API/src/RestWrapper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..921bd43988edb4bf8f35f5db60b5d76d253e0bf5
--- /dev/null
+++ b/API/src/RestWrapper.cpp
@@ -0,0 +1,168 @@
+#include "stdafx.hpp"
+
+#include "RestWrapper.hpp"
+#include "BackEnd.hpp"
+
+#include <cpprest/containerstream.h>
+
+using namespace concurrency;
+using namespace concurrency::streams;
+using namespace std;
+using namespace web;
+using namespace http;
+using namespace utility;
+using namespace web::http::experimental::listener;
+
+RestWrapper::RestWrapper(utility::string_t url) : m_listener(url)
+{
+  m_listener.support(methods::GET, std::bind(&RestWrapper::handle_get, this, std::placeholders::_1));
+  m_listener.support(methods::PUT, std::bind(&RestWrapper::handle_put, this, std::placeholders::_1));
+  m_listener.support(methods::POST, std::bind(&RestWrapper::handle_post, this, std::placeholders::_1));
+  m_listener.support(methods::DEL, std::bind(&RestWrapper::handle_delete, this, std::placeholders::_1));
+}
+
+void RestWrapper::_reply(int code, http_request message, const web::json::value &value, bool debug)
+{
+  http_response response(static_cast<unsigned short>(code));
+
+  response.headers().add(U("Content-Type"), U("application/json"));
+
+  if (debug)
+    ucout << "#: " << value << endl;
+
+  response.set_body(value);
+  message.reply(response);
+}
+
+void RestWrapper::handle_get(http_request message)
+{
+  auto uri = http::uri::decode(message.relative_uri().path());
+  ostringstream o;
+  {
+    auto tmp = http::uri::split_query(message.relative_uri().query());
+
+    o << '{';
+    for (auto it = tmp.begin(); it != tmp.end(); ++it)
+    {
+      if (it != tmp.begin())
+        o << ',';
+      o << '"' << it->first << "\":\"" << it->second << '"';
+    }
+    o << '}';
+  }
+  try
+  {
+    json::value obj;
+
+    int code = BackEnd::instance()->get(uri, o.str(), obj);
+
+    _reply(code, message, obj);
+  }
+  catch (const exception &e)
+  {
+    cout << "*** HANDLE_GET *** " << e.what() << " | " << message.relative_uri().path() << endl;
+  }
+};
+
+//
+// A POST of the dealer resource creates a new table and returns a resource for
+// that table.
+//
+void RestWrapper::handle_post(http_request message)
+{
+  container_buffer<std::string> inStringBuffer;
+
+  message.body().read_to_end(inStringBuffer).then([message, inStringBuffer](size_t /* bytesRead */) {
+    auto uri = http::uri::decode(message.relative_uri().path());
+    const std::string &data = inStringBuffer.collection();
+
+    // Perform actions here after reading line into a string...
+    try
+    {
+      json::value obj;
+      int code = BackEnd::instance()->post(uri, obj, data);
+
+      _reply(code, message, obj);
+    }
+    catch (const exception &e)
+    {
+      cout << "*** HANDLE_POST *** " << e.what() << " | " << message.relative_uri().path() << endl;
+    }
+  });
+};
+
+//
+// A DELETE of the player resource leaves the table.
+//
+void RestWrapper::handle_delete(http_request message)
+{
+  try
+  {
+    json::value obj;
+    obj["message"] = json::value::string(U("abc"));
+    _reply(status_codes::OK, message, obj);
+  } catch (const exception &e)
+  {
+    cout << "*** HANDLE_DEL *** " << e.what() << " | " << message.relative_uri().path() << endl;
+  }
+};
+
+//
+// A PUT to a table resource makes a card request (hit / stay).
+//
+void RestWrapper::handle_put(http_request /* message */)
+{
+}
+
+/*
+    ucout <<  message.to_string() << endl;
+
+    auto paths = uri::split_path(uri::decode(message.relative_uri().path()));
+    auto query = uri::split_query(uri::decode(message.relative_uri().query()));
+    auto queryItr = query.find(REQUEST);
+    if (paths.empty() || queryItr == query.end())
+    {
+        message.reply(status_codes::Forbidden, U("TableId and request are required."));
+    }
+    utility::string_t wtable_id = paths[0];
+    utility::string_t request = queryItr->second;
+    const utility::string_t table_id = wtable_id;
+
+    // Get information on a specific table.
+    auto found = s_tables.find(table_id);
+    if ( found == s_tables.end() )
+    {
+        message.reply(status_codes::NotFound);
+    }
+
+    auto table = std::static_pointer_cast<DealerTable>(found->second);
+
+    if ( request == BET )
+    {
+        table->Bet(message);
+    }
+    else if ( request == DOUBLE )
+    {
+        table->DoubleDown(message);
+    }
+    else if ( request == INSURE )
+    {
+        table->Insure(message);
+    }
+    else if ( request == HIT )
+    {
+        table->Hit(message);
+    }
+    else if ( request == STAY )
+    {
+        table->Stay(message);
+    }
+    else if ( request == REFRESH )
+    {
+        table->Wait(message);
+    }
+    else
+    {
+        message.reply(status_codes::Forbidden, U("Unrecognized request"));
+    }
+*/
diff --git a/API/src/audio.cpp b/API/src/audio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef281b30f720a63d408fdc4ac09d22e795ee0181
--- /dev/null
+++ b/API/src/audio.cpp
@@ -0,0 +1,279 @@
+#include "audio.hpp"
+#include "os.hpp"
+#include "Json.hpp"
+#include "utils.hpp"
+#include "features.hpp"
+#include "BackEnd.hpp"
+#include <iostream>
+#include <stdexcept>
+
+using namespace std;
+using namespace web;
+
+#define DSD_CONFIG_FILE "/var/www/config/dsd_config"
+
+namespace audio
+{
+json::value getRavennaInfo()
+{
+  json::value v;
+
+  if (Features::isActivated())
+  {
+    string t;
+    OS::exec_wait("grep \"snd_merging_rav - Merging RAVENNA\" /proc/asound/cards", t);
+
+    v[RAVENNA_PRESENT] = json::value::boolean(!t.empty() && OS::exists(RAVENNA_SOFTWARE));
+
+    int port = 9090;
+
+    if (OS::exists("/var/alsa-aes67-driver/merging_ravenna_daemon.conf"))
+    {
+      string p;
+      OS::exec_wait("grep web_app_port /var/alsa-aes67-driver/merging_ravenna_daemon.conf | cut -d '=' -f2", p);
+      port = stoi(p);
+    }
+    string h;
+    OS::exec_wait("hostname -I", h);
+    v[RAVENNA_HOST]     = json::value::string(h);
+    v[RAVENNA_PORT]     = json::value::number(port);
+    v[RAVENNA_PROTOCOL] = json::value::string("http");
+  } else {
+    v[RAVENNA_PRESENT] = json::value::boolean(false);
+  }
+
+  return v;
+}
+
+json::value getAudioCards()
+{
+  strings cards;
+  OS::exec_wait("aplay -l|grep ^card| sed -r 's/card\\ (.*):.*device\\ (.*):.*\\[(.*)\\]/hw:\\1,\\2~\\3/g'", cards);
+  size_t n = cards.size();
+
+  json::value v = json::value::array(n);
+
+  for (size_t idx = 0; idx < n; ++idx)
+  {
+    ostringstream samples;
+    const string &item = cards[idx];
+    string::size_type x = item.find('~');
+
+    if (x == string::npos || x < 2)
+      continue;
+
+    string plug = item.substr(0, x);
+    string::size_type c = plug.find(':');
+    string::size_type d = plug.find(',');
+    if (c == string::npos || c < 2)
+      continue;
+    if (d == string::npos || d < 2)
+      continue;
+
+    string card = plug.substr(c + 1, d - c - 1);
+    string device = plug.substr(d + 1);
+
+    strings capabilities;
+    OS::exec_wait("/usr/local/bin/alsa-capabilities -a " + plug + " 2>&1 >/dev/null", capabilities);
+
+    bool hasSamples = false;
+
+    for (auto it = capabilities.begin(); it != capabilities.end(); ++it)
+    {
+      if (it->find("usb audio class") != string::npos)
+      {
+        string usb = it->substr(it->find('=') + 2);
+        v[idx]["usb"] = json::value::string(U(usb == "(n/a)" ? "PLAYER.AUDIO_NON_USB"
+                                                             : usb));
+      }
+      else if (hasSamples == true && it->find("-") != string::npos)
+      {
+        break;
+      }
+      else if (hasSamples || it->find("samplerates") != string::npos)
+      {
+        // - samplerates (kHz) = U8:                 44.1 48 88.2 96 176.4 192
+        //                       S16_LE:             44.1 48 88.2 96 176.4 192
+        string::size_type n1 = it->find('=');
+        string::size_type n2 = it->find(':', n1 == string::npos ? 0 : n1);
+        string sample = n1 == string::npos ? it->substr(0, n2 + 1) : it->substr(n1 + 2, n2 - n1);
+        string rates = it->substr(n2 + 2);
+        utils::trim(sample);
+        utils::trim(rates);
+
+        if (hasSamples)
+          samples << "<br/>";
+        samples << sample << ' ' << rates;
+        hasSamples = true;
+      }
+    }
+
+    v[idx]["output"] = json::value::string(U(plug));
+    v[idx]["name"] = json::value::string(U(item.substr(++x)));
+    v[idx]["active"] = json::value::boolean(false);
+
+    // get playing sample rate
+    strings rates;
+    OS::exec_wait("cat /proc/asound/card" + card + "/pcm" + device + "p/sub0/hw_params", rates);
+    switch (rates.size())
+    {
+    case 1:
+      if (rates.front() == "closed")
+        v[idx]["rate"] = json::value::string(U("PLAYER.STATE.CLOSED"));
+      break;
+    case 7:
+    {
+      ostringstream o;
+      o << rates[2].substr(rates[2].find(' ') + 1)
+        << ' '
+        << rates[1].substr(rates[1].find(' ') + 1)
+        << rates[4].substr(rates[4].rfind(' '));
+      v[idx]["rate"] = json::value::string(U(o.str()));
+      break;
+    }
+    default:
+      //copy(rates.begin(), rates.end(), ostream_iterator<string>(cout, "\n"));
+      //cout << rates.size() << endl;
+      break;
+    }
+  }
+
+  return v;
+}
+
+void getVersion(string &version)
+{
+  OS::exec_wait("cat /proc/asound/version | awk 'NF>1{print $NF}'", version);
+  string::size_type n = version.length();
+  if (version[n - 1] == '.')
+    version = version.substr(0, n - 1);
+}
+
+json::value getStatus()
+{
+  string version;
+  getVersion(version);
+
+  string msg;
+  OS::exec_wait("dpkg -l | grep \"^ii  pulseaudio\" | wc -l", msg);
+
+  json::value v;
+  v["pulse"] = json::value::boolean(!msg.empty() && stoi(msg) > 0);
+  v["version"] = json::value::string(U(version));
+  v["cards"] = getAudioCards();
+  v[RAVENNA] = getRavennaInfo();
+
+  return v;
+}
+
+json::value removePulse(const string &)
+{
+  string version;
+  getVersion(version);
+
+  string msg;
+  OS::exec_wait("apt-get purge pulseaudio* -y 2> /dev/null;", msg);
+
+  json::value v;
+  v["pulse"] = json::value::boolean(false);
+  v["version"] = json::value::string(U(version));
+  v["cards"] = getAudioCards();
+  v[RAVENNA] = getRavennaInfo();
+  return v;
+}
+
+void startRavennaClient() {
+  json::value r = audio::getRavennaInfo();
+  if (r[audio::RAVENNA_PRESENT].as_bool()) {
+    string t;
+    OS::exec_wait("ps aux|grep Merging_Ravenna_Daemon", t);
+
+    cout << "Starting Ravenna client: ";
+    if (!t.empty()) {
+      cout << "Started" << endl;
+      OS::exec_nowait("/usr/local/bin/start_ravenna.sh");
+    } else {
+      cout << "Ravenna Client Already running" << endl;
+    }
+  }
+}
+
+void stopRavennaClient() {
+  json::value r = audio::getRavennaInfo();
+  if (r[audio::RAVENNA_PRESENT].as_bool()) {
+    cout << "Stopping Ravenna client" << endl;
+    OS::exec_nowait("/usr/local/bin/stop_ravenna.sh");
+  }
+}
+
+json::value getUsbId(const string &) {
+  json::value v;
+  string s;
+  OS::exec_wait("cat /proc/asound/*/usbid 2> /dev/null|head -1", s);
+  if (s.find("cat: ") == 0)
+    s = "";
+  v["usb_id"] = json::value::string(s);
+
+  return v;
+}
+
+json::value getDsdConfig(const string &) {
+
+  json::value v;
+  string contents;
+  if (BackEnd::instance()->isDSDKernel())
+  {
+    try {
+      if (OS::readTextFile(DSD_CONFIG_FILE, contents)) {
+        throw runtime_error ("XXX"); // v["format"] = json::value::string("none");
+      }
+      else
+      {
+        utils::trim(contents);
+        strings e;
+        utils::tokenise(contents, e, '-');
+        if (e.size() == 3) {
+          int i = stoi(e[1]);
+          v["usb_id"] = json::value::string(e[0]);
+          v["altset"] = json::value::string(i == 0? "1" : e[1]);
+          v["format"] = json::value::string(e[2]);
+          v["kernel"] = json::value::boolean(true);
+        }
+        else
+        {
+          throw runtime_error ("XXX"); // v["format"] = json::value::string("none");
+        }
+      }
+    }
+    catch (const exception & e)
+    {
+      v["kernel"] = json::value::boolean(true);
+      v["format"] = json::value::string("none");
+      v["usb_id"] = json::value::string("");
+      v["altset"] = json::value::string("1");
+    }
+  }
+  else
+  {
+    v["kernel"] = json::value::boolean(false);
+    v["format"] = json::value::string("none");
+    v["usb_id"] = json::value::string("");
+    v["altset"] = json::value::string("1");
+  }
+
+  return v;
+}
+
+void setDsdConfig(json::value & v)
+{
+  const string format(v["format"].as_string());
+  if (format == "none") {
+    OS::del(DSD_CONFIG_FILE);
+  } else {
+    ostringstream o;
+    o << v["usb_id"].as_string() << '-' << v["altset"].as_string() << '-' << format << endl;
+    // cout << "Format: (" << format <<')' << endl;
+    OS::saveTextFile(DSD_CONFIG_FILE, o.str()); 
+  }
+}
+} // namespace audio
diff --git a/API/src/browse.cpp b/API/src/browse.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..36b9737b07211b94198c8f5bd955ad188e1fee28
--- /dev/null
+++ b/API/src/browse.cpp
@@ -0,0 +1,162 @@
+#include "browse.hpp"
+#include "os.hpp"
+#include <fstream>
+#include <algorithm>
+#include <exception>
+#include <experimental/filesystem>
+
+using namespace std;
+using namespace web;
+namespace fs = std::experimental::filesystem;
+
+#define PATH_PREFIX "/media/"
+
+json::value Browse::getFolderContents(web::json::value input){
+  const string path = http::uri::decode(input["path"].as_string()); 
+  const fs::path pathToShow{PATH_PREFIX + input["name"].as_string() + path};
+
+  vector<string> directory, file;
+
+  for (const auto& entry : fs::directory_iterator(pathToShow)) {
+    const auto filenameStr = entry.path().filename().string();
+    if (path == "/" && filenameStr == "ram") continue;
+
+    if (is_directory(entry)) {
+      directory.push_back(filenameStr);
+    }
+    else if (is_regular_file(entry)) {
+      file.push_back(filenameStr);
+    }
+  }
+  // sort the order by name ascending
+  sort(directory.begin(), directory.end());
+  sort(file.begin(), file.end());
+
+  json::value v;
+  size_t c = 0;
+  json::value & d = v["items"] = json::value::array(directory.size() + file.size());
+
+  for (auto it = directory.begin(); it != directory.end(); ++it, ++c) {
+    json::value & item = d[c];
+    item["name"] = json::value::string(U(*it));
+    item["folder"] = json::value::boolean(true);
+    item["selected"] = json::value::boolean(false);
+  }
+  
+  for (auto it = file.begin(); it != file.end(); ++it, ++c) {
+    json::value & item = d[c];
+    item["name"] = json::value::string(U(*it));
+    item["folder"] = json::value::boolean(false);
+    item["selected"] = json::value::boolean(false);
+  }
+  return v;
+}
+
+json::value Browse::createFolder(json::value data) {
+  const string & share = data["share"].as_string();
+  json::array &items = data["payload"].as_array();
+  string t;
+  int code = 0;
+  for (auto it = items.begin(); it != items.end() && code == 0; ++it) {
+    // cout << "mkdir -p " PATH_PREFIX + share + '/' + it->as_string() << endl;
+    code = OS::exec_wait("mkdir -p " PATH_PREFIX + share + '/' + it->as_string(), t);
+  }
+  json::value v;
+
+  v["code"] = json::value::number(code);
+  v["message"] = json::value::string(U(t));
+
+  return v;
+}
+
+json::value Browse::addFiles(json::value data) {
+  // "path":"a/b","share":"music","uploads":["package-lock.json","sample.dsd"
+  const string & path = PATH_PREFIX + data["share"].as_string() + '/' + data["path"].as_string();
+  json::array &items = data["uploads"].as_array();
+  for (auto it = items.cbegin(); it != items.cend(); ++it)
+  {
+    const string & fn = it->as_string();
+    OS::move("/var/cache/lighttpd/uploads/" + fn, path);
+  }
+  json::value v;
+  v["message"] = json::value::string(U("COMMON.OK"));
+  return v;
+}
+
+json::value Browse::delFiles(web::json::value data) {
+  json::array &items = data["payload"].as_array();
+  const string & share = data["share"].as_string();
+  ostringstream o;
+  o << "rm -rf";
+  for (auto it = items.cbegin(); it != items.cend(); ++it)
+  {
+    // OS::del(PATH_PREFIX + it->as_string());
+    o << " \"" PATH_PREFIX << share << it->as_string() << '"';
+  }
+  o << " 2>&1";
+
+  string t;
+  int code = OS::exec_wait(o.str(), t);
+  json::value v;
+  v["code"]    = json::value::number(code);
+  v["message"] = json::value::string(U(t));
+  return v;
+}
+
+json::value Browse::copyFiles(web::json::value data){
+  json::value v;
+
+  try {
+    const string & share = data["share"].as_string();
+    json::array &items = data["payload"].as_array();
+    ostringstream o;
+
+    o << "cp -rf ";
+
+    if (share == "music") {
+      for (auto it = items.cbegin(); it != items.cend(); ++it)
+      {
+        o << " \"" PATH_PREFIX << share << it->as_string() << '"';
+      }
+    } else if (share == "playlists") {
+      for (auto it = items.cbegin(); it != items.cend(); ++it)
+      {
+        ifstream infile(PATH_PREFIX + share + it->as_string());
+        string line;
+        int count = 0;
+        while (std::getline(infile, line)) {
+          if (line.length() && line[0] != '#' && OS::exists(line))
+          {
+            o << " \"" << line << '"';
+            ++count;
+          }
+        }
+        if (count == 0) {
+          throw invalid_argument("BROWSE.ERROR_NO_FILES");
+        }
+      }
+    }
+
+    o << " \"" PATH_PREFIX << "music/ram/\" 2>&1";
+    string t;
+    // cout << "Cmd: (" << o.str() << ')' << endl;
+    int code = OS::exec_wait(o.str(), t);
+
+    v["code"] = json::value::number(code);
+    v["message"] = json::value::string(U(t));
+  } catch (const exception & e) {
+    v["code"] = json::value::number(1);
+    v["message"] = json::value::string(U(e.what()));
+  }
+
+  return v;
+}
+
+json::value Browse::replaceFiles(web::json::value data){
+  const string & share = data["share"].as_string();
+  string t;
+  OS::exec_wait("rm -rf " PATH_PREFIX + share + "/ram/*", t);
+
+  return copyFiles(data);
+}
+
diff --git a/API/src/dashboard.cpp b/API/src/dashboard.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8df1fd641e1e56905102b636f3e0f55d3276c487
--- /dev/null
+++ b/API/src/dashboard.cpp
@@ -0,0 +1,201 @@
+#include "BackEnd.hpp"
+#include "os.hpp"
+#include "network.hpp"
+#include "version.hpp"
+#include "snakesys.hpp"
+#include "Quotes.hpp"
+
+#include <ostream>
+#include <iostream>
+#include <iterator>
+
+using namespace std;
+using namespace web;
+
+void getSnakeoilVersion(strings &key, strings &value);
+void getCPUInfo(strings &key, strings &value);
+void getSysInfo(strings &key, strings &value);
+void getRamInfo(strings &key, strings &value);
+
+static Quotes _quotes;
+
+void getSnakeoilVersion(strings &key, strings &value)
+{
+  key.clear();
+  value.clear();
+
+  string ubuntu;
+
+  Config &c = BackEnd::instance()->config();
+
+  ostringstream activation;
+  activation << (c.isActivated() ? "ACTIVATION.ACTIVATED"
+                                 : "ACTIVATION.NOT_ACTIVATED");
+
+  OS::exec_wait("lsb_release -d|cut -f2", ubuntu);
+
+  value.push_back(Version::getVersion());
+  value.push_back(activation.str());
+  value.push_back(ubuntu);
+  key.push_back("DASHBOARD.VERSION.VERSION");
+  key.push_back("DASHBOARD.VERSION.ACTIVATION");
+  key.push_back("DASHBOARD.VERSION.OS");
+}
+
+void getCPUInfo(strings &key, strings &value)
+{
+  key.clear();
+  value.clear();
+
+  key.push_back("DASHBOARD.INFO.CPU.ARCHITECTURE");
+  key.push_back("DASHBOARD.INFO.CPU.OP_MODE");
+  key.push_back("DASHBOARD.INFO.CPU.CPU");
+  key.push_back("DASHBOARD.INFO.CPU.THREAD");
+  key.push_back("DASHBOARD.INFO.CPU.MODEL");
+  key.push_back("DASHBOARD.INFO.CPU.SPEED");
+  key.push_back("DASHBOARD.INFO.CPU.L1");
+  key.push_back("DASHBOARD.INFO.CPU.L2");
+  key.push_back("DASHBOARD.INFO.CPU.L3");
+  value.resize(9);
+
+  strings data;
+  OS::exec_wait("lscpu", data);
+
+  size_t idx;
+  for (auto it = data.begin(); it != data.end(); ++it)
+  {
+    if (it->find("Architecture") == 0)
+      idx = 0;
+    else if (it->find("CPU op-mode(s)") == 0)
+      idx = 1;
+    else if (it->find("CPU(s)") == 0)
+      idx = 2;
+    else if (it->find("Thread(s) per core:") == 0)
+      idx = 3;
+    else if (it->find("Model name:") == 0)
+      idx = 4;
+    else if (it->find("CPU MHz:") == 0)
+      idx = 5;
+    else if (it->find("L1d cache:") == 0)
+      idx = 6;
+    else if (it->find("L2 cache:") == 0)
+      idx = 7;
+    else if (it->find("L3 cache:") == 0)
+      idx = 8;
+    else
+      continue;
+
+    utils::trim((value[idx] = it->substr(it->find(':') + 2)));
+  }
+
+  for (auto it = value.begin(); it != value.end(); ++it)
+  {
+    if (it->empty())
+      *it = BackEnd::instance()->translate("COMMON.NONE");
+  }
+  // update Threads by CPU to show total number of threads
+  value[3] = to_string(stoi(value[2]) * stoi(value[3]));
+}
+
+void getSysInfo(strings &key, strings &value)
+{
+  key.clear();
+  value.clear();
+  string kernel,
+      clocksource,
+      uptime;
+
+  OS::exec_wait("uname -r", kernel);
+  OS::exec_wait("cat /sys/devices/system/clocksource/clocksource0/current_clocksource", clocksource);
+  OS::exec_wait("uptime", uptime);
+
+  key.push_back("DASHBOARD.INFO.SYSTEM.HOSTNAME");
+  key.push_back("DASHBOARD.INFO.SYSTEM.ZEROCONF");
+  key.push_back("DASHBOARD.INFO.SYSTEM.KERNEL");
+  key.push_back("DASHBOARD.INFO.SYSTEM.CLOCKSOURCE");
+  key.push_back("DASHBOARD.INFO.SYSTEM.UPTIME");
+  const string &hostname = network::getHostname();
+  value.push_back(hostname);
+  value.push_back(hostname + ".local");
+  value.push_back(kernel);
+  value.push_back(clocksource);
+  value.push_back(uptime);
+}
+
+void getRamInfo(strings &key, strings &value)
+{
+  key.clear();
+  value.clear();
+
+  key.push_back("DASHBOARD.INFO.RAM.TOTAL");
+  key.push_back("DASHBOARD.INFO.RAM.USED");
+  key.push_back("DASHBOARD.INFO.RAM.FREE");
+  key.push_back("DASHBOARD.INFO.RAM.CACHED");
+
+  OS::exec_wait("free|awk \"NR==2\"|tr -s \" \"|cut -d ' ' -f2,3,4,6", value, ' ');
+}
+
+namespace dashboard
+{
+json::value qotd();
+json::value getElements();
+
+json::value qotd()
+{
+  Json q;
+  q.append("quote", _quotes.getQuote());
+  q.append("author", _quotes.getAuthor());
+  q.append("url", _quotes.getURL());
+
+  return q.value();
+}
+
+json::value getElements()
+{
+  strings kVer, vVer,
+      kCpu, vCpu,
+      kSys, vSys,
+      kRam, vRam;
+
+  getSnakeoilVersion(kVer, vVer);
+  getCPUInfo(kCpu, vCpu);
+  getSysInfo(kSys, vSys);
+  getRamInfo(kRam, vRam);
+
+  Json version;
+  Json system;
+  Json activation;
+
+  version.addChild("snakeoil", kVer, vVer);
+  version.addChild("update", snakesys::getLastUpdateCheck());
+
+  system.addChild("cpu", kCpu, vCpu);
+  system.addChild("system", kSys, vSys);
+  system.addChild("ram", kRam, vRam);
+
+  Config &c = BackEnd::instance()->config();
+  if (c.isActivated()) {
+    string name, mail, code;
+
+    c.getRegoName(name);
+    c.getRegoMail(mail);
+    c.getRegoCode(code);
+
+    activation.addChild("name", json::value::string(U(name)));
+    activation.addChild("mail", json::value::string(U(mail)));
+    activation.addChild("code", json::value::string(U(code)));
+  } else {
+    activation.addChild("name", json::value::string(U("")));
+    activation.addChild("mail", json::value::string(U("")));
+    activation.addChild("code", json::value::string(U("")));
+  }
+
+
+  Json elements;
+  elements.addChild("version", version);
+  elements.addChild("system",  system);
+  elements.addChild("activation", activation);
+
+  return elements.value();
+}
+} // namespace dashboard
diff --git a/API/src/features.cpp b/API/src/features.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2241486259c31a377ca17fb0d538002fcff5c251
--- /dev/null
+++ b/API/src/features.cpp
@@ -0,0 +1,62 @@
+#include "features.hpp"
+#include "BackEnd.hpp"
+#include "Json.hpp"
+#include "os.hpp"
+
+#define FEATURES "features"
+#define F_ACTIVATED "activated"
+#define F_CGROUP "cgroup"
+#define F_CPUSET "cpuset"
+#define F_EXFAT "exfat"
+#define F_ECASOUND "ecasound"
+using namespace web;
+
+json::value _getFeatures();
+
+json::value _getFeatures()
+{
+  json::value v;
+
+  v[F_ACTIVATED] = json::value::boolean(Features::isActivated());
+  v[F_CGROUP] = json::value::boolean(Features::hasCGroup());
+  v[F_CPUSET] = json::value::boolean(Features::hasCPUSet());
+  v[F_EXFAT] = json::value::boolean(Features::hasFSExFat());
+  v[F_ECASOUND] = json::value::boolean(Features::hasEcaSound());
+
+  return v;
+}
+
+void Features::getFeatures(json::value &v)
+{
+  v[FEATURES] = _getFeatures();
+}
+
+void Features::getFeatures(Json &v)
+{
+  v.append(FEATURES, _getFeatures());
+}
+
+bool Features::isActivated()
+{
+  return BackEnd::instance()->config().isActivated();
+}
+
+bool Features::hasCGroup()
+{
+  return OS::exists("/usr/bin/cset") && OS::exists("/sys/fs/cgroup/cpuset");
+}
+
+bool Features::hasCPUSet()
+{
+  return OS::exists("/usr/bin/cset");
+}
+
+bool Features::hasFSExFat()
+{
+  return OS::exists("/sbin/mount.exfat");
+}
+
+bool Features::hasEcaSound()
+{
+  return OS::exists("/usr/bin/ecasound");
+}
diff --git a/API/src/library.cpp b/API/src/library.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f8450196bdaee4c16dbe5ed83a6ed3a1d4a1118
--- /dev/null
+++ b/API/src/library.cpp
@@ -0,0 +1,352 @@
+#include "library.hpp"
+#include "utils.hpp"
+#include "os.hpp"
+#include "Json.hpp"
+#include "BackEnd.hpp"
+#include "features.hpp"
+#include <sstream>
+#include <set>
+#include <iterator>
+#include <iomanip>
+
+using namespace web;
+using namespace std;
+
+namespace library
+{
+string getMounted()
+{
+  strings lines;
+  OS::exec_wait("df --output=source,size,avail,pcent,fstype,target -h |"
+                "sed -e '/^udev/ d' -e '/^tmpfs/ d'",
+                lines);
+
+  ostringstream o;
+  o << "[";
+  if (lines.size() > 1)
+  {
+    // now count the colums
+    vector<pair<string::size_type, string::size_type>> indices;
+    string::size_type start = 0;
+    string::size_type end = 0;
+    bool isSpace = false;
+    for (char *ch = &lines[0][0]; *ch; ++ch, ++end)
+    {
+      if (*ch == ' ')
+      {
+        isSpace = true;
+      }
+      else if (isSpace && *ch != ' ')
+      {
+        isSpace = false;
+        indices.push_back(make_pair(start, end - 1 - start));
+        start = end;
+      }
+    }
+    indices.back().second = string::npos;
+
+    for (auto it = lines.begin() + 1; it != lines.end(); ++it)
+    {
+      if (it->find("/dev/loop") == 0) continue;
+
+      string source = it->substr(indices[0].first, indices[0].second);
+      string size = it->substr(indices[1].first, indices[1].second);
+      string avail = it->substr(indices[2].first, indices[2].second);
+      string used = it->substr(indices[3].first, indices[3].second);
+      string type = it->substr(indices[4].first, indices[4].second);
+      string path = it->substr(indices[5].first, indices[5].second);
+
+      utils::trim(source);
+      utils::trim(size);
+      utils::trim(avail);
+      utils::trim(used);
+      utils::trim(type);
+      utils::trim(path);
+
+      if (type == "fuseblk")
+        OS::exec_wait("lsblk -no fstype " + source, type);
+      else if (source == "cgmfs")
+        continue;
+
+      if (it != lines.begin() + 1)
+        o << ',';
+
+      o << "{\"source\": \"" << source << "\","
+                                          "\"size\": \""
+        << size << "\","
+                   "\"available\": \""
+        << avail << "\","
+                    "\"used\": \""
+        << used << "\","
+                   "\"type\": \""
+        << type << "\","
+                   "\"path\": \""
+        << path << "\""
+        << "}";
+    }
+  }
+  // check RAMDISK
+  Config & cfg = BackEnd::instance()->config();
+  if (cfg.getRamdiskEnable()) {
+      if (!o.str().empty()) o << ',';
+      int size = atoi(cfg.getRamdiskSize().c_str());
+      int used = OS::getRamdiskUsed();
+      
+      ostringstream oUsed;
+      string units;
+      if (size > 1024) {
+        units = 'G';
+        size /= 1024;
+        used /= 1024;
+      } else {
+        units  = "M";
+      }
+
+      if (size == 0) size = 1;
+      oUsed << fixed << setprecision(0) << (((double)size-used)/size*100.0);
+      o << "{\"source\": \"" << cfg.getRamdiskType() << "\","
+                                          "\"size\": \""
+        << cfg.getRamdiskSize() << units << "\","
+                   "\"available\": \""
+        << (size-used) << units << "\","
+                    "\"used\": \""
+        << oUsed.str() << "%\","
+                   "\"type\": \""
+        << cfg.getRamdiskType() << "\","
+                   "\"path\": \"/media/music/ram\""
+        << "}";
+  }
+
+  o << "]";
+
+  return o.str();
+}
+
+void getUninitialised(strings &ln)
+{
+  ln.clear();
+  OS::exec_wait("for DEV in /dev/sd[a-z]; do if [ -b $DEV ]; then if [ ! `lsblk ${DEV} | wc -l` -gt 2 ]; then echo $DEV; fi; fi; done",
+                ln);
+}
+
+bool initDisk(const string &disk, string &log)
+{
+  ostringstream o;
+
+  o << "/sbin/parted " << disk << " -s mklabel gpt 2>&1 &&"
+    << "/sbin/parted " << disk << " -s mkpart primary ext4 0 100% 2>&1 &&"
+    << "/sbin/mkfs.ext4 " << disk << "1 2>&1";
+
+  bool code = OS::exec_wait(o.str(), log);
+  if (code == 0)
+  {
+    log = BackEnd::instance()->translate("LIBRARY.FORMAT_OK");
+  }
+  return code;
+}
+
+string getUnmounted()
+{
+  strings msgs;
+
+  string cmd = "for DEV in /dev/sd[a-z]?; do"
+               "  if [ -b $DEV ]; then"
+               "    if [ \"`lsblk $DEV -n |wc -w`\" -eq \"6\" ]; then"
+               "      VALUE=\"`blkid $DEV -s TYPE -o value`\";"
+               "      if [ \"$VALUE\" = \"ntfs\" ] || [ \"$VALUE\" = \"ext4\" ] || [ \"$VALUE\" = \"vfat\" ]; then"
+               "        echo \"{\\\"partition\\\":\\\"${DEV}\\\", \\\"filesystem\\\":\\\"$VALUE\\\"}\";"
+               "      fi;"
+               "   fi;"
+               "  fi;"
+               "done;";
+
+  OS::exec_wait(cmd, msgs);
+  ostringstream o;
+  o << '[' << endl;
+  for (auto it = msgs.begin(); it != msgs.end(); ++it)
+  {
+    if (it != msgs.begin())
+      o << ',' << endl;
+    o << "  " << *it;
+  }
+  o << endl
+    << ']' << endl;
+
+  return o.str();
+}
+
+bool setCredentialsCifs(const string &username, const string &password, const string &domain)
+{
+  ostringstream o;
+  o << "username=" << username << endl
+    << "password=" << password << endl
+    << "domain=" << domain << endl;
+
+  return OS::saveTextFile("/root/.credentials", o.str());
+}
+
+string getCredentialsCifs()
+{
+  string name, password, domain;
+  if (OS::exists("/root/.credentials"))
+  {
+    string text;
+    OS::readTextFile("/root/.credentials", text);
+    strings contents;
+    utils::tokenise(text, contents, '\n');
+    for (auto it = contents.begin(); it != contents.end(); ++it)
+    {
+      if (it->find("password=") == 0)
+        password = it->substr(9);
+      else if (it->find("username=") == 0)
+        name = it->substr(9);
+      else if (it->find("domain=") == 0)
+        domain = it->substr(7);
+    }
+  }
+  ostringstream o;
+  o << "{ \"username\": \"" << name << "\","
+                                       "\"password\": \""
+    << password << "\","
+                   "\"domain\": \""
+    << domain << "\"}";
+
+  return o.str();
+}
+
+json::value saveConfig(const std::string &data)
+{
+  string message;
+  int code = 0;
+  int line = -1;
+  json::value problem;
+
+  set<string> types;
+  types.insert("ext4");
+  types.insert("cifs");
+  types.insert("ntfs");
+  types.insert("vfat");
+  types.insert("nfs");
+  if (Features::hasFSExFat())
+    types.insert("exFAT");
+
+  set<string> dMedia,
+      dMount;
+
+  string err;
+  json::value orig;
+  Config &config = BackEnd::instance()->config();
+  int update = 0;
+
+  json::value d = json::value::parse(data);
+
+  // check and make sure there are no problems before saving
+  for (size_t i = 0; i < d["mediaItems"].size(); ++i)
+  {
+    json::value &obj = d["mediaItems"][i];
+
+    if (!(obj.has_field("media") && obj.has_field("mount") && obj.has_field("type")))
+    {
+      err = "LIBRARY.INVALID_ENTRY";
+      goto endFunc;
+    }
+    const string &media = obj["media"].as_string();
+    const string &mount = obj["mount"].as_string();
+    const string &type = obj["type"].as_string();
+
+    if (dMedia.find(media) != dMedia.end())
+    {
+      line = static_cast<int>(i);
+      problem = obj;
+      err = "LIBRARY.MEDIA_DUPLICATE";
+      goto endFunc;
+    }
+    else if (dMount.find(mount) != dMount.end())
+    {
+      line = static_cast<int>(i);
+      problem = obj;
+      err = "LIBRARY.MOUNT_POINT_DUPLICATE";
+      goto endFunc;
+    }
+    else if (types.find(type) == types.end())
+    {
+      line = static_cast<int>(i);
+      problem = obj;
+      err = "LIBRARY.MOUNT_TYPE_INVALID";
+      goto endFunc;
+    }
+    else if (media.empty())
+    {
+      line = static_cast<int>(i);
+      problem = obj;
+      err = "LIBRARY.MEDIA_BLANK";
+      goto endFunc;
+    }
+    else if (!OS::exists(media) && type != "cifs" && type != "nfs")
+    {
+      line = static_cast<int>(i);
+      problem = obj;
+      err = "LIBRARY.MEDIA_MISSING";
+      goto endFunc;
+    }
+    dMedia.insert(media);
+    dMount.insert(mount);
+  }
+
+  // check CIFS creds
+  /*
+   // Do Samba XXX_TJ
+    $sLogin    = $_POST["smb_login"];
+    $sPassword = $_POST["smb_passwd"];
+    $sDomain   = $_POST["smb_workgroup"];
+    $sTxt="";
+    if (!(empty($sLogin)||empty($sPassword)||empty($sDomain)))
+      $sTxt="USERNAME=${sLogin}\nPASSWORD=${sPassword}\nDOMAIN=${sDomain}";
+   */
+
+  // all clear, save to database
+  update += setCredentialsCifs(d["cred_cifs"]["username"].as_string(),
+                               d["cred_cifs"]["password"].as_string(),
+                               d["cred_cifs"]["domain"].as_string());
+
+  orig = config.getMusicConfig();
+
+  if (orig != d && ((code = config.setMusicConfig(data, message)) == 0))
+    ++update;
+
+  if (update)
+  {
+    OS::umount(orig);
+
+    if (OS::mount(d["mediaItems"], message))
+    {
+      err = message;
+      goto endFunc;
+    }
+    message = "LIBRARY.SAVED";
+  }
+  else
+  {
+    message = "LIBRARY.NOT_SAVED";
+  }
+
+endFunc:
+  if (!err.empty())
+  {
+    message = err;
+    code = 501;
+  }
+
+  Json j;
+  j.append("code", code);
+  j.append("message", message);
+
+  if (line >= 0)
+  {
+    j.append("line", ++line);
+    j.append("entry", problem);
+  }
+
+  return j.value();
+}
+}; // namespace library
diff --git a/API/src/main.cpp b/API/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8294c67bb2d88651e3a6b666219896f324654823
--- /dev/null
+++ b/API/src/main.cpp
@@ -0,0 +1,253 @@
+/**
+ ** Snakeoil OS API
+ **/
+#include "stdafx.hpp"
+#include "version.hpp"
+#include "RestWrapper.hpp"
+#include "os.hpp"
+#include "BackEnd.hpp"
+#include "snakesys.hpp"
+#include <stdexcept>
+#include <string>
+#include <signal.h>
+#include <stdio.h>
+#include <iomanip>
+#include <curl/curl.h>
+
+extern std::unique_ptr<RestWrapper> g_httpSnakeoilAPI;
+
+std::unique_ptr<RestWrapper> g_httpSnakeoilAPI;
+using namespace std;
+using namespace web;
+using namespace http;
+using namespace utility;
+using namespace http::experimental::listener;
+
+void on_initialize(const string_t &address);
+void on_shutdown();
+void gracekill(int num);
+int showHelp();
+
+void on_initialize(const string_t &address)
+{
+  uri_builder uri(address);
+  uri.append_path(U("api"));
+
+  auto addr = uri.to_string();
+  g_httpSnakeoilAPI = std::unique_ptr<RestWrapper>(new RestWrapper(addr));
+  g_httpSnakeoilAPI->open().wait();
+
+  ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl;
+
+  return;
+}
+
+void on_shutdown()
+{
+  g_httpSnakeoilAPI->close().wait();
+  return;
+}
+
+inline bool isInt(const string &s)
+{
+  if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+')))
+    return false;
+
+  char *p;
+  strtol(s.c_str(), &p, 10);
+
+  return (*p == 0);
+}
+extern bool running;
+
+bool running = true;
+
+/*
+  Handle kils
+ */
+void gracekill(int num)
+{
+  // we might use this handler for many signals
+  switch (num)
+  {
+  case SIGTERM:
+  case SIGINT:
+    running = false;
+    // clean up code.
+    break;
+  }
+}
+
+#define STR_HELP    "--help"
+#define STR_VERSION "--version"
+#define STR_DIAG    "--diag"
+#define STR_WEBROOT "--webroot"
+#define STR_RECOVER "--recover"
+#define STR_EXIT    "--exit"
+
+//#define STR_SHIELD  "--cpuset-shield"
+
+int showHelp()
+{
+  const int width = 10;
+
+  ucout << "Snakeoil OS " << Version::getVersion() << endl
+        << endl
+        << setw(width) << setfill(' ') << right << STR_VERSION
+        << ": Show version and exit" << endl
+        << setw(width) << setfill(' ') << right << STR_DIAG
+        << ": Generate diagnostics file" << endl
+        << setw(width) << setfill(' ') << right << STR_WEBROOT
+        << ": Change web root directory (testing only)" << endl
+        << setw(width) << setfill(' ') << right << STR_EXIT
+        << ": Exit API server" << endl
+        << setw(width) << setfill(' ') << right << STR_RECOVER
+        << ": Recover Snakeoil with firmware" << endl
+        << setw(width) << setfill(' ') << right << STR_HELP
+        << ": Show basic help" << endl
+        //       << setw(width) << setfill(' ') << right << STR_SHIELD
+        //          << ": return 1 if CPUset shield is enabled. 0 otherwise." << endl
+        << endl;
+
+  return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  string webroot = "/var/www/";
+  string recover = "/media/music/recover.fw";
+
+  // initialise the RNG
+  srandom(static_cast<unsigned int>(time(NULL)));
+
+  signal(SIGTERM, gracekill);
+  signal(SIGINT, gracekill);
+  try
+  {
+    for (int c = 1; c < argc; ++c)
+    {
+      string opt(argv[c]);
+
+      if (STR_HELP == opt)
+      {
+        return showHelp();
+      }
+      else if (STR_VERSION == opt)
+      {
+        cout << Version::getVersion();
+        return 0;
+      }
+      else if (STR_DIAG == opt)
+      {
+        cout << snakesys::getSystemDiagnostics("/media/music/diagnostics.tar.bz2");
+        return 0;
+      }
+      else if (opt.compare(0, strlen(STR_WEBROOT), STR_WEBROOT) == 0)
+      {
+        webroot = opt.substr(10);
+        if (webroot.rfind('/') != webroot.length() - 1)
+          webroot += '/';
+        if (!OS::exists(webroot))
+        {
+          cout << "webroot directory don't exist: " << webroot << endl;
+          return 1;
+        }
+      } else if (opt.compare(0, strlen(STR_RECOVER), STR_RECOVER) == 0)
+      {
+        recover = opt.substr(10);
+
+        if (!OS::exists(recover))
+        {
+          cout << "Recovery firmware don't exist: " << recover << endl;
+          return 1;
+        }
+      }
+      else if (opt.compare(0, strlen(STR_EXIT), STR_EXIT) == 0)
+      {
+        cout << "Exiting API Rest server" << endl;
+        CURL *curl;
+        CURLcode res;
+        
+        static const char *postthis = "";
+        
+        curl = curl_easy_init();
+        if(curl) {
+          curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:30511/api/system/restart_be");
+          curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis);
+        
+          /* if we don't provide POSTFIELDSIZE, libcurl will strlen() by
+             itself */ 
+          curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis));
+        
+          /* Perform the request, res will get the return code */ 
+          res = curl_easy_perform(curl);
+          /* Check for errors */ 
+          if(res != CURLE_OK)
+            fprintf(stderr, "curl_easy_perform() failed: %s\n",
+                    curl_easy_strerror(res));
+        
+          /* always cleanup */ 
+          curl_easy_cleanup(curl);
+        }
+        return 0;
+      }
+      else
+        throw runtime_error("Invalid options: " + opt);
+    }
+
+    const bool skipStartPlayers = OS::exists(recover);
+
+    BackEnd *be = BackEnd::instance();
+    be->init(skipStartPlayers, webroot, &running);
+
+    if (skipStartPlayers)
+    {
+      ucout  << "Recovery firmware found. Please wait..." << endl;
+      string arch;
+      OS::exec_wait("uname -m", arch);
+
+      string tmp;
+      OS::exec_wait("mv -f " + recover + " /var/cache/lighttpd/uploads/recover-" + arch + ".fw", tmp);
+      json::value v = snakesys::update_snakeoil("{\"name\":\"recover-" + arch + ".fw\"}");
+      int code = v["code"].as_integer();
+      if (code) {
+        ucout << "Invalid firmware. Ignoring recovery." << endl;
+      }
+      else {
+        ucout << "Firmware recovered. Restarting snakeoil-rest." << endl;
+
+        BackEnd::instance()->destroy();
+      }
+
+      return code;
+    }
+
+    // go through all the cmdline arguments
+    const utility::string_t port = "30511";
+
+    // listen globally
+    utility::string_t address = U("http://127.0.0.1:");
+    address.append(port);
+
+    on_initialize(address);
+
+    // Now then start the players
+
+    while (running)
+    {
+      sleep(1);
+    }
+  }
+  catch (const exception &e)
+  {
+    ucout << U("*** ERROR *** ") << U(e.what()) << endl;
+    running = false;
+    return 1;
+  }
+
+  on_shutdown();
+  ucout << U("Exiting...") << endl;
+
+  return 0;
+}
+
diff --git a/API/src/network.cpp b/API/src/network.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e148c439d3fa83a1fc1c104740ddeca916d208c3
--- /dev/null
+++ b/API/src/network.cpp
@@ -0,0 +1,287 @@
+#include "network.hpp"
+#include "os.hpp"
+#include "stdafx.hpp"
+#include "BackEnd.hpp"
+
+#include <fstream>
+#include <string.h>
+#include <iostream>
+#include <map>
+#include <algorithm>
+
+using namespace std;
+using namespace web;
+
+void _getDNS(std::string &dns);
+bool _setResolvConf(const string &dnsServer);
+
+bool _setResolvConf(const string &dnsServer)
+{
+  ostringstream dns;
+
+  dns << "# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)" << endl
+      << "#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN" << endl
+      << "nameserver " << dnsServer << endl;
+
+  return OS::saveTextFile("/etc/resolv.conf", dns.str());
+}
+
+void _getDNS(std::string &dns)
+{
+  OS::exec_wait("grep ^nameserver /etc/resolv.conf |"
+                "awk 'NR==1'| cut -d ' ' -f2",
+                dns);
+}
+
+namespace network
+{
+extern strings nics;
+
+void init()
+{
+  string dns("");
+  _getDNS(dns);
+
+  // /etc/resolv.conf file don't have a DNS entry
+  if (dns.empty())
+  {
+    BackEnd::instance()->config().getNetDNS(dns);
+
+    if (!dns.empty())
+    {
+      _setResolvConf(dns);
+    }
+  }
+}
+
+string getDNS()
+{
+  string dns;
+  _getDNS(dns);
+
+  if (dns.empty())
+  {
+    BackEnd::instance()->config().getNetDNS(dns);
+  }
+  return dns;
+}
+
+string getIPV4(const string &iface)
+{
+  string ipv4;
+
+  OS::exec_wait("ifconfig " + iface + "|grep -E inet\\ addr:\\|inet\\ | "
+                "sed -e 's/.*inet\\s\\(.*\\)\\s.*/\\1/g' "
+                    "-e 's/.*addr:\\(.*\\)\\s.*/\\1/g'|awk '{print $1}'", ipv4);
+
+  return ipv4;
+}
+
+string getIPV4Mask(const string &iface)
+{
+  string ipv4mask;
+  OS::exec_wait("ifconfig " + iface + "|grep -i mask|"
+                "sed -e 's/.*netmask\\s\\(.*\\)\\s.*/\\1/g' "
+                    "-e 's/.*Mask:\\(.*\\)/\\1/g'|awk '{print $1}'",
+        ipv4mask);
+
+  return ipv4mask;
+}
+
+string getIPV4MTU(const string &iface)
+{
+  string ipv4mtu;
+    OS::exec_wait("ifconfig "+ iface + " |grep -i mtu|sed -e 's/.*MTU:\\(.*\\)\\s.*/\\1/g' -e 's/.*mtu\\s\\(.*\\)/\\1/g'", ipv4mtu);
+
+  return ipv4mtu.empty() ? "1500"
+                         : ipv4mtu;
+}
+
+string getMode(const string &iface)
+{
+  string mode;
+  OS::exec_wait("grep \"iface " + iface + " inet \" /etc/network/interfaces|cut -d' ' -f4", mode);
+
+  if (mode.empty())
+    mode = "dhcp";
+
+  return mode;
+}
+
+string getGateway()
+{
+  string gateway;
+  OS::exec_wait("route -n|grep ^0.0.0.0|awk 'NR==1'|cut -d' ' -f10", gateway);
+  return gateway;
+}
+
+string getHostname()
+{
+  string hostname;
+  OS::exec_wait("echo \"`hostname`\"", hostname);
+  return hostname;
+}
+
+void getNICs(strings &list)
+{
+  char buffer[255];
+  ifstream f("/proc/net/dev", ios::in);
+
+  f.getline(buffer, 254);
+  f.getline(buffer, 254);
+
+  while (f.good())
+  {
+    f.getline(buffer, 254);
+
+    for (int i = 0, j = 0; buffer[i]; ++i)
+    {
+      switch (buffer[i])
+      {
+      case ' ':
+      case '\t':
+        ++j;
+        break;
+      case ':':
+        buffer[i] = '\0';
+        // add a check to exclude lo
+        if (strncmp(&buffer[j], "lo", 2) != 0 &&
+            strncmp(&buffer[j], "sit", 3) != 0)
+        {
+          list.push_back(&buffer[j]);
+        }
+        break;
+      }
+    }
+  }
+  sort(list.begin(), list.end());
+}
+
+void getNIC(const string &interface, strings &keys, strings &values)
+{
+  strings lines;
+  values.resize(5, string());
+
+  OS::exec_wait("ethtool -i " + interface + " | awk 'NR<=2'", lines);
+  OS::exec_wait("ifconfig " + interface + " |grep -i -E ether\\|Hwaddr|"
+                  "sed -e 's/.*HWaddr\\s\\(.*\\)/\\1/g' "
+                      "-e 's/.*ether\\s\\(.*\\)\\s.*/\\1/g'|awk '{print $1}'", values[2]);
+
+  values[4] = getIPV4MTU(interface);
+
+  if (lines.empty())
+    return;
+
+  values[0] = utils::substr(lines[0], ':');
+  values[1] = utils::substr(lines[1], ':');
+  values[3] = getIPV4(interface);
+  if (values[3].empty())
+    values[3] = "NETWORK.NO_IPV4";
+  else
+    values[3] += '/' + getIPV4Mask(interface);
+
+  keys.push_back("NETWORK.DRIVER");
+  keys.push_back("NETWORK.VERSION");
+  keys.push_back("NETWORK.HW_ADDRESS");
+  keys.push_back("NETWORK.IPV4");
+  keys.push_back("NETWORK.MTU");
+}
+
+int setNetworkConfig(const string &data, string &msg)
+{
+  int modified = 0;
+
+  try
+  {
+    json::value input = json::value::parse(data);
+
+    // write /etc/network/interfaces
+    ostringstream o;
+    o << "# interfaces(5) file used by ifup(8) and ifdown(8)" << endl
+      << "auto lo" << endl
+      << "iface lo inet loopback" << endl
+      << endl;
+
+    int count = 0;
+    for (size_t i = 0; i < input["card"].size(); ++i)
+    {
+      auto card = input["card"].at(i);
+
+      auto s = card["mode"].as_string();
+
+      if (s == "manual")
+      {
+        o << "auto " << card["name"].as_string() << endl
+          << "iface " << card["name"].as_string() << " inet manual" << endl
+          << endl;
+      }
+      else if (s == "static")
+      {
+        o << "auto " << card["name"].as_string() << endl
+          << "iface " << card["name"].as_string() << " inet static" << endl
+          << "address " << card["ipv4"].as_string() << endl
+          << "netmask " << card["netmask"].as_string() << endl;
+
+        // only for activated users
+        if (BackEnd::instance()->config().isActivated())
+        {
+          json::value & mtu = card["mtu"];
+          if (mtu.is_number())
+            o << "mtu " << mtu.as_integer() << endl;
+          else if(mtu.is_string())
+            o << "mtu " << mtu.as_string() << endl;
+          else
+            throw invalid_argument("MTU has an invalid object type");
+        }
+
+        if (count == 0)
+        {
+          ++count;
+          o << "gateway " << input["gateway"].as_string() << endl
+            << "dns-nameservers " << input["dns"].as_string() << endl;
+        }
+        o << endl;
+      }
+      else if (s == "dhcp")
+      {
+        o << "auto " << card["name"].as_string() << endl
+          << "iface " << card["name"].as_string() << " inet dhcp" << endl
+          << endl;
+      }
+      else
+      {
+        throw runtime_error("Invalid mode: " + s);
+      }
+    }
+
+    // once I reach here, means everything is working
+    modified += OS::saveTextFile("/etc/network/interfaces", o.str());
+
+    // save hostname
+    if (OS::saveTextFile("/etc/hostname", input["hostname"].as_string()))
+    {
+      ++modified;
+      string output;
+      OS::exec_wait("hostname " + input["hostname"].as_string(), output);
+    }
+    // save DNS
+    if (count)
+    {
+      modified += _setResolvConf(input["dns"].as_string());
+
+      BackEnd::instance()->config().setNetDNS(input["dns"].as_string());
+    }
+  }
+  catch (const exception &e)
+  {
+    msg = e.what();
+
+    return 1;
+  }
+
+  msg = modified ? "NETWORK.SAVED"
+                 : "NETWORK.NOT_SAVED";
+
+  return 0;
+}
+} // namespace network
diff --git a/API/src/os.cpp b/API/src/os.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..02d257bb829bb784d83f7ea17fc921acc02bd25e
--- /dev/null
+++ b/API/src/os.cpp
@@ -0,0 +1,1051 @@
+#include "os.hpp"
+#include "utils.hpp"
+#include "BackEnd.hpp"
+#include "snakeoil.hpp"
+#include "task.hpp"
+
+#include <mcrypt.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+using namespace std;
+using namespace web;
+
+int OS::_count = 0;
+OS::_Tasks OS::_tasks;
+
+string OS::_arch;
+int    OS::_mount;
+
+typedef struct UsbEntry
+{
+  string location;
+  string vendor;
+  int port;
+  bool power;
+  string device;
+
+  explicit UsbEntry(const string &v, const string &l) : location(l), vendor(v), port(0), power(false) {}
+} UsbEntry;
+
+typedef std::vector<UsbEntry> UsbEntries;
+
+pplx::details::reader_writer_lock_impl OS::_lock;
+
+Task OS::_empty("No tasks found");
+
+// prototype
+bool _getUSBStatus(const string &line, UsbEntry &usb);
+
+OS::OS() {
+  _mount = 0;
+
+  //cout << "_mount: " << _mount << endl;
+}
+
+OS::~OS() {}
+
+const string & OS::getArch() {
+  if (_arch.empty())
+  {
+    OS::exec_wait("uname -m", _arch);
+  }
+
+  return _arch;
+}
+
+bool OS::exists(const string &name)
+{
+  struct stat buffer;
+  return (stat(name.c_str(), &buffer) == 0);
+}
+
+void OS::del(const string &name)
+{
+  if (exists(name))
+    remove(name.c_str());
+}
+
+void OS::umount(json::value d)
+{
+  string msg;
+  for (size_t i = 0; i < d.size(); ++i)
+  {
+    ostringstream o;
+    o << "umount -f \"/media/music/" << d[i]["mount"].as_string() << '"';
+
+    OS::exec_wait(o.str(), msg);
+  }
+}
+
+int OS::mount(json::value d, string &msg)
+{
+  msg = "";
+  int code = 0;
+  for (size_t i = 0; i < d.size(); ++i)
+  {
+    ostringstream o;
+    const string &media = d[i]["media"].as_string();
+    const string &mount = d[i]["mount"].as_string();
+    const string &type = d[i]["type"].as_string();
+    string options;
+
+    o << "mount " << media << " \"/media/music/" << mount << '"'
+      << " -t " << type;
+
+    if (d[i].has_field("options"))
+      options = d[i]["options"].as_string();
+
+    if (type == "cifs")
+    {
+      string contents;
+      readTextFile("/root/.credentials", contents);
+      strings lines;
+      utils::tokenise(contents, lines, '\n');
+
+      if (!lines.empty() && lines.front().length() > 10 && lines.front().substr(0, 9) == "username=")
+      {
+        options += "noserverino,nounix,credentials=/root/.credentials";
+      }
+      else
+      {
+        options += "noserverino,nounix";
+      }
+    }
+    else if (type == "ntfs")
+    {
+      string o;
+      OS::exec_wait("ntfsfix -d " + media, o);
+    }
+
+    mkDir("/media/music/" + mount);
+    if (!options.empty())
+      o << " -o \"" << options << '"';
+
+    o << " 2>&1";
+
+    string output;
+    code += exec_wait(o.str(), output);
+    if (output.empty())
+    {
+      exec_wait("chmod 777 \"/media/music/" + mount + "\"", output);
+    }
+    else
+    {
+      msg += output + '\n';
+    }
+  }
+
+  return code > 0;
+}
+
+int OS::exec_wait(const string &cmd, strings &results, char delim)
+{
+  string t;
+  int code = exec_wait(cmd, t);
+  utils::tokenise(t, results, delim);
+
+  return code;
+}
+
+int OS::exec_wait(const string &cmd, const shared_ptr<Task> &output)
+{
+  if (debug())
+    return 1;
+  FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
+  if (!pipe)
+  {
+    output->console << "ERROR: Cannot open pipes." << endl;
+    return 1;
+  }
+
+  char buffer[128];
+  int c;
+
+  while (!feof(pipe))
+  {
+    // if (fgets(buffer, 128, pipe) != NULL)
+    if ((c = fgetc(pipe)) != EOF)
+      output->console << (char) c;
+
+    usleep(20);
+  }
+
+  int status = pclose(pipe);
+  output->code = WEXITSTATUS(status);
+
+  return output->code;
+}
+
+int OS::exec_wait(const string &cmd, string &result)
+{
+  if (debug())
+    return 1;
+  result = "";
+  FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
+  if (!pipe)
+  {
+    result = "ERROR";
+    return 1;
+  }
+
+  char buffer[128];
+  while (!feof(pipe))
+  {
+    if (fgets(buffer, 128, pipe) != NULL)
+      result += buffer;
+    usleep(200);
+  }
+
+  utils::trim(result);
+  int status = pclose(pipe);
+  return WEXITSTATUS(status);
+}
+
+shared_ptr<Task> OS::getTicketOutput()
+{
+  _lock.lock();
+  int ticket = _count++;
+  auto output = _tasks[ticket] = make_shared<Task>(Task());
+  _lock.unlock();
+
+  return output;
+}
+
+int OS::exec_nowait(const string &cmd)
+{
+  auto t = pplx::create_task([cmd]() -> int {
+    FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
+    if (!pipe)
+    {
+      return 1;
+    }
+    char buffer[256];
+    while (!feof(pipe))
+    {
+      fgets(buffer, 255, pipe);
+      usleep(200);
+    }
+    int status = pclose(pipe);
+    return WEXITSTATUS(status);
+  });
+
+  return 0;
+}
+
+int OS::exec_nowait(const string &cmd, const string &wait, string &msg)
+{
+  if (debug())
+    return 1;
+
+  // grab a running number
+  auto output = getTicketOutput();
+  output->cmd = cmd;
+  output->wait = wait;
+
+  auto t = pplx::create_task([cmd, output, msg]() -> int {
+    FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
+    if (!pipe)
+    {
+      output->console << "Cannot execute command: " << cmd << endl;
+      output->code = 1;
+      return 1;
+    }
+    else
+    {
+      char buffer[256];
+      while (!feof(pipe))
+      {
+        if (fgets(buffer, 255, pipe) != NULL)
+          output->console << buffer;
+        usleep(200);
+      }
+    }
+
+    snakeoil::chprio();
+    output->done = true;
+
+    int status = pclose(pipe);
+    output->code = WEXITSTATUS(status);
+    return output->code;
+  });
+
+  return 0;
+}
+
+int OS::exec_nowait(const string &cmd, shared_ptr<Task> task)
+{
+  if (debug())
+    return 1;
+
+  task->cmd = cmd;
+
+  auto t = pplx::create_task([cmd, task]() -> int {
+    FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
+    if (!pipe)
+    {
+      task->console << "Cannot execute command: " << cmd << endl;
+      task->code = 1;
+      return 1;
+    }
+    else
+    {
+      char buffer[256];
+      while (!feof(pipe))
+      {
+        if (fgets(buffer, 255, pipe) != NULL)
+          task->console << buffer;
+        usleep(200);
+      }
+    }
+
+    task->done = true;
+
+    snakeoil::chprio();
+    int status = pclose(pipe);
+    task->code = WEXITSTATUS(status);
+    return task->code;
+  });
+
+  return task->code;
+}
+
+int OS::setTicketDone(shared_ptr<Task> task, string &msg)
+{
+  _lock.lock();
+  task->done = true;
+  const string & s = task->console.str();
+  utils::cleanLineFeed(s, msg);
+  if (msg.empty()) msg = s;
+
+  int code = task->code;
+  _lock.unlock();
+
+  return code;
+}
+
+void OS::getTasks(vector<int> &jobs)
+{
+  jobs.clear();
+  _lock.lock();
+  for (auto it = _tasks.begin(); it != _tasks.end(); ++it)
+    jobs.push_back(it->first);
+
+  _lock.unlock();
+}
+
+const Task &OS::getTask(int ticket)
+{
+  auto it = _tasks.find(ticket);
+  return (it == _tasks.end()) ? _empty
+                              : *it->second;
+}
+
+void OS::removeTask(int ticket)
+{
+  auto it = _tasks.find(ticket);
+  if (it != _tasks.end())
+    _tasks.erase(it);
+}
+
+void OS::mkDir(const string &dirName, __mode_t umask)
+{
+  struct stat sb;
+  strings path;
+  utils::tokenise(dirName, path, '/');
+  ostringstream p;
+  p << '/';
+  for (auto it = path.begin(); it != path.end(); ++it)
+  {
+    p << *it << '/';
+    if (stat(p.str().c_str(), &sb) == -1)
+    {
+      mkdir(p.str().c_str(), umask);
+    }
+  }
+}
+
+void OS::move(const std::string & src, const std::string & dst) {
+  ostringstream o;
+  o << "mv -f \"" << src << "\" " << dst;
+  string t;
+
+  OS::exec_wait(o.str(), t);
+}
+
+bool OS::readTextFile(const string &fn, string &contents)
+{
+  bool x;
+  if ((x = exists(fn)))
+  {
+    ifstream t(fn);
+
+    t.seekg(0, ios::end);
+    contents.reserve(static_cast<size_t>(t.tellg()));
+    t.seekg(0, ios::beg);
+
+    contents.assign((istreambuf_iterator<char>(t)),
+                    istreambuf_iterator<char>());
+    t.close();
+  }
+
+  return !x;
+}
+
+bool OS::saveTextFile(const string &fn, const string &contents)
+{
+  string orig;
+  readTextFile(fn, orig);
+
+  if (orig == contents)
+    return false;
+
+  ofstream out(fn);
+  if (!out.good())
+    throw runtime_error("Cannot write file: " + fn);
+
+  out << contents;
+  out.close();
+
+  return true;
+}
+
+bool OS::debug()
+{
+  return exists("/var/www/debug");
+}
+
+bool OS::compatible(const string &fn)
+{
+  const string & arch = getArch();
+
+  // pass on generic straight away
+  if (fn.find("-generic") != string::npos)
+    return true;
+
+  if (arch == "x86_64")
+  {
+    return (fn.find('-' + arch) != string::npos ||
+            fn.find("-amd64") != string::npos ||
+            fn.find("_amd64") != string::npos);
+  }
+  else if (arch == "armv7l")
+  {
+    //cout << "ARCH: " << fn << ' ' << (fn.find("-armv7l") != string::npos) << endl;
+    return fn.find("-armv7l") != string::npos;
+  }
+
+  return false;
+}
+
+OS::Format OS::decrypt(const string &inFile, const string &outFile, shared_ptr<Task> task)
+{
+  BackEnd *be = BackEnd::instance();
+  Format format = FORMAT_UNKNOWN;
+
+  try
+  {
+    MCRYPT td;
+    int i;
+    char *key;
+    char password[21];
+    char block_buffer;
+    char *IV;
+    size_t keysize = 19; /* 128 bits */
+    
+    key = static_cast<char *>(calloc(1, keysize));
+    strcpy(password, "6j2^7NFrZ_&8Q=cz5q7V");
+
+    /* Generate the key using the password */
+    /*  mhash_keygen( KEYGEN_MCRYPT, MHASH_MD5, key, keysize, NULL, 0, password, strlen(password));
+     */
+    memmove(key, password, keysize); //strlen(password));
+    char cipher[] = "twofish";
+    char cfb[] = "cfb";
+    td = mcrypt_module_open(cipher, NULL, cfb, NULL);
+    if (td == MCRYPT_FAILED)
+    {
+      throw runtime_error(be->translate("UPDATE.FIRMWARE.DECRYPT_ERROR"));
+    }
+
+    IV = static_cast<char *>(malloc(static_cast<size_t>(mcrypt_enc_get_iv_size(td))));
+    
+    /* Put random data in IV. Note these are not real random data,
+     * consider using /dev/random or /dev/urandom.
+     */
+    IV[0] = 103;
+    IV[1] = -58;
+    IV[2] = 105;
+    IV[3] = 115;
+    IV[4] = 81;
+    IV[5] = -1;
+    IV[6] = 74;
+    IV[7] = -20;
+    IV[8] = 41;
+    IV[9] = -51;
+    IV[10] = -70;
+    IV[11] = -85;
+    IV[12] = -14;
+    IV[13] = -5;
+    IV[14] = -29;
+    IV[15] = 70;
+
+    i = mcrypt_generic_init(td, key, static_cast<int>(keysize), IV);
+    if (i < 0)
+    {
+      mcrypt_perror(i);
+      throw runtime_error(be->translate("UPDATE.FIRMWARE.DECRYPT_ERROR"));
+    }
+    
+    /* Encryption in CFB is performed in bytes */
+    FILE *in = fopen(inFile.c_str(), "rb");
+    FILE *out = fopen(outFile.c_str(), "wb");
+
+    if (in == NULL)
+      throw runtime_error("Cannot open input: " + inFile);
+    else if (out == NULL)
+      throw runtime_error("Cannot open output: " + outFile);
+    
+    while (fread(&block_buffer, 1, 1, in) == 1)
+    {
+      mdecrypt_generic(td, &block_buffer, 1);
+    
+      fwrite(&block_buffer, 1, 1, out);
+    }
+
+    mcrypt_generic_deinit(td);
+    
+    mcrypt_module_close(td);
+    fclose(in);
+    fclose(out);
+    
+    /// -----------------------
+    // check for integrity
+    if (system(("bunzip2 -t " + outFile).c_str()))
+    {
+      throw runtime_error(be->translate("UPDATE.FIRMWARE.ERROR"));
+    }
+    else
+    {
+      task->console << be->translate("UPDATE.FIRMWARE.VERIFYING") << endl;
+
+      int nowhere;
+      nowhere = system("rm /var/tmp/www.so_os.www -rf");
+      nowhere = system(("tar -xjf " + outFile + " -C /var/tmp").c_str());
+
+      if (exists("/var/tmp/www.so_os.www/snakeoil.php") &&
+          exists("/var/tmp/www.so_os.www/php.snakeoil") &&
+          exists("/var/tmp/www.so_os.www/update.php") &&
+          exists("/var/tmp/www.so_os.www/upgrade.sh") &&
+          exists("/var/tmp/www.so_os.www/top.php"))
+      {
+        format = FORMAT_OLD_FIRMWARE;
+      }
+      else if (exists("/var/tmp/www.so_os.www/html/humans.txt") &&
+               exists("/var/tmp/www.so_os.www/html/index.html") &&
+               exists("/var/tmp/www.so_os.www/html/robots.txt") &&
+               exists("/var/tmp/www.so_os.www/html/initial.css") &&
+               exists("/var/tmp/www.so_os.www/update_snakeoil.sh"))
+      {
+        format = FORMAT_FIRMWARE;
+      }
+      else if (exists("/var/tmp/www.so_os.www/upgrade.sh"))
+      {
+        format = FORMAT_MODULE;
+      }
+    }
+  }
+  catch (const exception & e )
+  {
+    task->console << "ERROR: " << e.what() << endl;
+  }
+
+  return format;
+}
+
+void OS::updateGrub(const shared_ptr<Task> &,
+                    string &version, string &clocksource, string &options)
+{
+  if (options == "none")
+    options = "";
+  if (getArch() == "armv7l")
+  {
+    // cout << "updateGrub(" << version << ", " << clocksource << ", " << options << ')' << endl;
+   exec_nowait("sed -i \"s/\\(.*\\)kernel=.*\\(.*\\)/\\1kernel=kernel-"
+                              + version + "\\2/g\" /boot/config.txt");
+
+  }
+  else
+  {
+    if (version.find("vmlinuz-") == 0)
+    {
+      system(("sed -e \"s/@NEW_CLOCKSOURCE@/" + clocksource + "/g\" "
+                                                            "-e \"s/@NEW_VERSION@/" +
+              version.substr(8) + "/g\" "
+                                "-e \"s/@NEW_OPTIONS@/" +
+              options + "/g\" "
+                      "/var/www/config/grub.template > /etc/default/grub &&"
+                      "update-grub 2> /dev/null")
+               .c_str());
+    }
+    else
+    {
+      system(("sed -e \"s/@NEW_CLOCKSOURCE@/" + clocksource + "/g\" "
+                                                            "-e \"s/@NEW_VERSION@/" +
+            version + "/g\" "
+                      "-e \"s/@NEW_OPTIONS@/" +
+            options + "/g\" "
+                      "/var/www/config/grub.template > /etc/default/grub &&"
+                      "update-grub 2> /dev/null")
+               .c_str());
+    }
+  }
+}
+
+string OS::getClocksource()
+{
+  string x;
+  OS::exec_wait("cat /sys/devices/system/clocksource/clocksource0/current_clocksource", x);
+  return x;
+}
+
+json::value OS::getAvailClocksource()
+{
+  strings list;
+  exec_wait("cat /sys/devices/system/clocksource/clocksource0/available_clocksource", list, ' ');
+
+  json::value v = json::value::array(list.size());
+
+  size_t c = 0;
+  for (auto it = list.begin(); it != list.end(); ++it, ++c)
+    v[c] = json::value::string(U(*it));
+
+  return v;
+}
+
+json::value OS::stopUhubCtl()
+{
+  json::value v;
+
+  v["code"] = json::value::number(0);
+  v["message"] = json::value::string(U("OK"));
+
+  OS::exec_nowait("killall uhubctl");
+
+  return v;
+}
+
+string OS::getKernelOptions()
+{
+  string cmd;
+  exec_wait("cat /proc/cmdline", cmd);
+
+  json::value opts = getAvailKernelOptions();
+  for (size_t idx = 0; idx < opts.size(); ++idx)
+  {
+    const string &tmp = opts[idx].as_string();
+    if (cmd.find(tmp) != string::npos)
+      return tmp;
+  }
+  return "none";
+}
+
+json::value OS::getAvailKernelOptions()
+{
+  json::value v;
+  size_t c = 0;
+
+  if (getArch() == "armv7l")
+  {
+    v = json::value::array(1);
+    v[c++] = json::value::string(U("none"));
+  }
+  else
+  {
+    v = json::value::array(7);
+    v[c++] = json::value::string(U("none"));
+    v[c++] = json::value::string(U("acpi=noirq"));
+    v[c++] = json::value::string(U("acpi=ht"));
+    v[c++] = json::value::string(U("noapic"));
+    v[c++] = json::value::string(U("pnpacpi=off"));
+    v[c++] = json::value::string(U("nolapic"));
+    v[c++] = json::value::string(U("noacpi"));
+  }
+
+  return v;
+}
+
+string OS::getGrubKernel()
+{
+  string grub;
+  // cat /etc/default/grub |grep GRUB_DEFAULT
+  // GRUB_DEFAULT=0
+  // GRUB_DEFAULT="1>Ubuntu, with Linux 4.4.9-rt17-amd64-dsd"
+
+  if (getArch() == "armv7l")
+  {
+    exec_wait("grep kernel= /boot/config.txt |cut -d'=' -f2", grub);
+    grub = &grub[7];
+  }
+  else
+  {
+    exec_wait("grep ^GRUB_DEFAULT /etc/default/grub | sed 's/.*\\ with\\ Linux\\ \\(.*\\)\"/\\1/g\'", grub);
+    if (grub.empty() || grub == "GRUB_DEFAULT=0")
+      grub = getBootKernel();
+  }
+
+  return grub;
+}
+
+string OS::getBootKernel()
+{
+  string v;
+  exec_wait("uname -r|sed 's/\\(.*\\)-[0-9]\\{8\\}.*/\\1/g'", v);
+
+  // for Pi
+  if (getArch() == "armv7l")
+  {
+    if (exists("/boot/kernel-" + v))
+    {
+      return v;
+    }
+
+    return "kernel7.img";
+  }
+
+  // for normal computers
+  if (exists("/boot/vmlinuz-" + v))
+  {
+    return v;
+  }
+  // don't match
+  string::size_type n1 = v.find("amd64");
+  string::size_type n2 = v.find("x64");
+  string::size_type n3 = v.find("i32");
+
+  string v2 = v;
+  if (n1 != string::npos)
+  {
+    v2.replace(n1, 5, "x64");
+  }
+  else if (n2 != string::npos)
+  {
+    v2.replace(n2, 3, "amd64");
+  }
+  else if (n3 != string::npos)
+  {
+    v2.replace(n3, 3, "i686");
+  }
+
+  return v2;
+}
+
+json::value OS::getAvailBootKernels()
+{
+  DIR *dir;
+  string bootPath = "/boot/";
+  strings kernels;
+
+  const string k = getArch() == "armv7l"? "kernel-"
+                                        : "vmlinuz-";
+  const int n = getArch() == "armv7l" ? 7
+                                      : 8;
+  if ((dir = opendir(bootPath.c_str())))
+  {
+    struct dirent *ent;
+    while ((ent = readdir(dir)) != NULL)
+    {
+      string path(ent->d_name);
+      // ignore the . and .. files
+      if (path == "." || path == "..")
+        continue;
+      if (path.compare(0, n, k) == 0)
+      {
+        kernels.push_back(&path[n]);
+      }
+    }
+    sort(kernels.begin(), kernels.end());
+    closedir(dir);
+  }
+
+  json::value v = json::value::array(kernels.size());
+
+  size_t c = 0;
+  for (auto it = kernels.begin(); it != kernels.end(); ++it, ++c)
+  {
+    v[c] = json::value::string(U(*it));
+  }
+  return v;
+}
+
+bool _getUSBStatus(const string &line, UsbEntry &usb)
+{
+  strings elems;
+  utils::tokenise(line, elems, ' ');
+
+  string::size_type n = elems.size();
+  if (n >= 4)
+  {
+    usb.port = std::stoi(elems[1].substr(0, elems[1].length() - 1));
+
+    if (n == 4)
+    {
+      usb.power = elems[3] == "power" ? true : false;
+      usb.device = "SNAKEOIL.MANAGE_USB.NO_DEVICE";
+    }
+    else
+    {
+      usb.power = true;
+      bool start = false;
+      for (string::size_type idx = 4; idx < n; ++idx)
+      {
+        if (elems[idx].find('[') != string::npos)
+          start = true;
+        if (start)
+        {
+          if (!usb.device.empty())
+            usb.device += ' ';
+          usb.device += elems[idx];
+        }
+      }
+      n = usb.device.find(' ');
+      if (n != string::npos && n > 2)
+        usb.device = usb.device.substr(n + 1, usb.device.length() - n - 2);
+    }
+
+    return false;
+  }
+  return true;
+}
+
+web::json::value OS::getUSBPorts(bool read)
+{
+  strings ports;
+  int code = 0 ;
+  if (read)
+  {
+    code = OS::exec_wait("uhubctl", ports);
+  }
+
+  size_t c = 0;
+  string vendor;
+  string location;
+  UsbEntries usb;
+
+  if (code == 0)
+  {
+    for (auto it = ports.begin(); it != ports.end(); ++it)
+    {
+      string::size_type vIdx = it->find("Current status for hub");
+
+      if (vIdx != string::npos)
+      {
+        vIdx = it->find('[', vIdx);
+        if (vIdx != string::npos)
+        {
+          vendor = it->substr(++vIdx, it->find(' ', vIdx) - vIdx-1);
+        }
+        location = it->substr(23, it->find(' ', 23)-23);
+      }
+      else
+      {
+        usb.push_back(UsbEntry(vendor, location));
+        if (_getUSBStatus(*it, usb.back()))
+        {
+          usb.pop_back();
+        }
+      }
+    }
+  }
+
+  json::value v = json::value::array(usb.size());
+  for (auto it = usb.begin(); it != usb.end(); ++it, ++c)
+  {
+/*
+    cout << " Vendor: (" << it->vendor << ')' << endl
+        << "location: (" << it->location << ')' << endl
+         << "   Port: " << it->port << endl
+         << "  power: " << it->power << endl
+         << " device: " << it->device << endl;
+*/
+    v[c]["location"]= json::value::string(U(it->location));
+    v[c]["vendor"] = json::value::string(U(it->vendor));
+    v[c]["port"] = json::value::number(it->port);
+    v[c]["power"] = json::value::boolean(it->power);
+    v[c]["device"] = json::value::string(U(it->device));
+  }
+
+  return v;
+}
+
+web::json::value OS::resetUSB()
+{
+  string msg;
+  OS::exec_nowait("for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; "
+                  "do "
+                  "echo \"${i##*/}\" > \"${i%/*}/unbind\";"
+                  "sleep 1;"
+                  "echo \"${i##*/}\" > \"${i%/*}/bind\";"
+                  "done");
+
+  json::value v;
+  v["code"] = json::value::number(0);
+  return v;
+}
+
+bool OS::setUSBPorts(json::value v, string &usb_off)
+{
+  json::value current = getUSBPorts();
+  bool changed = false;
+
+  map<string, map<string, string> > on, off;
+  ostringstream save;
+
+  for (uint i = 0; i < v.size(); ++i)
+  {
+    bool power = v[i]["power"].as_bool();
+    // Only need to remember OFF USB ports
+    if (!power)
+    {
+      if (!save.str().empty())
+        save << ';';
+      save << v[i]["location"].as_string() << ',' << v[i]["vendor"].as_string() << ',' << v[i]["port"].as_integer();
+    }
+
+    if (current[i]["power"].as_bool() != power)
+    {
+      changed = true;
+      (power ? on : off)[v[i]["location"].as_string()][v[i]["vendor"].as_string()] +=
+          to_string(v[i]["port"].as_integer());
+    }
+  }
+
+  if (changed)
+  {
+    for (auto it = on.begin(); it != on.end(); ++it)
+    {
+      for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) 
+      {
+        //cout << "@: uhubctl -l " + it->first + " -n " + it2->first + " -p " + it2->second + " -a 1 -e" << endl;
+        OS::exec_nowait("uhubctl -l " + it->first + " -n " + it2->first + " -p " + it2->second + " -a 1 -e");
+      }
+    }
+
+    for (auto it = off.begin(); it != off.end(); ++it)
+    {
+      for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) 
+      {
+        // cout << "@: uhubctl -l " + it->first + " -n " + it2->first + " -p " + it2->second + " -a 0 -e" << endl;
+        OS::exec_nowait("uhubctl -l " + it->first + " -n " + it2->first + " -p " + it2->second + " -a 0 -e");
+      }
+    }
+  }
+  // save all Off stuffs to database
+  usb_off = save.str();
+  //cout << changed << "###" << usb_off << endl;
+  return changed;
+}
+
+int OS::getFreeRAM() {
+  string s_free;
+  OS::exec_wait("free --mega|grep Mem:|awk '{print $7}'", s_free);
+  return atoi(s_free.c_str());
+}
+
+void OS::mountRamdisk() 
+{
+  if (_mount)
+    unmountRamdisk();
+  Config & cfg = BackEnd::instance()->config();
+
+  if (cfg.getRamdiskEnable() && _mount == 0) {
+    ostringstream o;
+    string rslt;
+
+    o << "mkdir -p /media/music/ram; mount -t " << cfg.getRamdiskType() << " -o size="
+      << cfg.getRamdiskSize() << "m " << cfg.getRamdiskType() << " /media/music/ram";
+    ++_mount;
+    exec_wait(o.str(), rslt);
+    //cout << "Command: " << o.str() << endl;
+  } else {
+    //cout << "Not doing anything " << _mount << " " << cfg.getRamdiskEnable()  << endl;
+  }
+}
+
+void OS::unmountRamdisk() {
+  if (_mount) {
+    string rslt;
+    exec_wait("umount -f /media/music/ram;rmdir /media/music/ram", rslt);
+    --_mount;
+  }
+  //cout << "Unmount RAM disk" << endl;
+}
+
+int OS::getRamdiskUsed()
+{
+  string rslt;
+  OS::exec_wait("du -BM /media/music/ram|awk '{print $1}'|sed 's/M$//g'", rslt);
+  return atoi(rslt.c_str());
+}
+
+bool OS::isRamdiskOK()
+{
+  string rslt;
+  OS::exec_wait("mount|grep \"/media/music/ram\"", rslt);
+
+  return !rslt.empty();
+}
+
+void OS::fixPhpUploadLimit(int max)
+{
+  strings files;
+  exec_wait("grep -e post_max_size -e upload_max_filesize /etc/php/* -R", files);
+
+  bool restartWWW = false;
+  for (auto it = files.begin(); it != files.end(); ++it) {
+    string::size_type t = it->rfind(':');
+    if (t != string::npos) {
+      const string fn = it->substr(0, t);
+      // only work on the file if it's php.ini
+      string::size_type n = fn.length();
+      if (n > 8 && fn.rfind("/php.ini") == n-8) {
+        const string old = it->substr(t+1);
+        const string::size_type cut = old.rfind("=");
+        string s_size = old.substr(cut+1);
+        utils::trim(s_size);
+
+        // only keep numbers
+        string units;
+        for (auto nn = 0; s_size[nn]; ++nn) {
+          if (!(s_size[nn] >= '0' && s_size[nn] <= '9')) {
+            units += s_size[nn];
+            s_size[nn] = '\0';
+          }
+        }
+
+        int size = atoi(s_size.c_str());
+        if (size < max) {
+          // Size under, need to fix
+          string replace = old.substr(0, cut);
+          utils::trim(replace);
+          //cout << "Fix: Fn: (" << fn << ") Text: (" << old << ") Size: (" << size << ") Units: (" << units <<')' << endl;
+          ostringstream cmd;
+          cmd << "sed -i " << fn << " -e \"s/"<< replace << "[ ]*\\=[ ]*" << size << units
+              << "/" << replace << "\\ \\=\\ " << max << units << "/g\"";
+          //cout << "  > " << cmd.str() << endl;
+          string rslt;
+          exec_wait(cmd.str(), rslt);
+          restartWWW = true;
+        } else {
+          //cout << " OK: Fn: (" << fn << ") Text: (" << old << ") Size: (" << size << ')' << endl;
+        }
+      }
+    }
+  }
+
+  if (restartWWW) {
+    //cout << "Restarting web server" << endl;
+    OS::exec_nowait("systemctl restart lighttpd");
+  }
+}
diff --git a/API/src/players.cpp b/API/src/players.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c89736f7e61be8d3b4925fafe5bff5b93389628
--- /dev/null
+++ b/API/src/players.cpp
@@ -0,0 +1,666 @@
+#include "players.hpp"
+#include "utils.hpp"
+#include "features.hpp"
+#include "BackEnd.hpp"
+#include "os.hpp"
+#include "snakeoil.hpp"
+#include "audio.hpp"
+#include "task.hpp"
+#include "time.hpp"
+
+#include <dirent.h>
+#include <iostream>
+
+using namespace std;
+using namespace web;
+
+void Players::init()
+{
+  string msg;
+  OS::exec_wait("alsactl restore", msg);
+}
+
+enum
+{
+  UNKNOWN,
+  PLAYER_NAME,
+  INIT,
+  PROGRAM_FILE,
+  MANUAL_CONFIG,
+  CONFIG_FILE,
+  PLAYER_START,
+  PLAYER_STOP,
+  EXTRA_OPTIONS,
+  HELP_URL,
+  INSTALL,
+  UNINSTALL,
+  START_VNC,
+  ORDER,
+  SERVER,
+  HAS_CLIENT,
+  CLIENT_LIST,
+  MAC_ADDRESS,
+  REMOTE,
+  ALSA_SETUP,
+  WIZARD,
+  CUSTOM_AUDIO,
+  GROUP,
+  INFO
+};
+
+Players::Players()
+{
+  if (_lookup.empty())
+  {
+    _lookup["PLAYER_NAME"] = PLAYER_NAME;
+    _lookup["INIT"] = INIT;
+    _lookup["PROGRAM_FILE"] = PROGRAM_FILE;
+    _lookup["MANUAL_CONFIG"] = MANUAL_CONFIG;
+    _lookup["CONFIG_FILE"] = CONFIG_FILE;
+    _lookup["PLAYER_START"] = PLAYER_START;
+    _lookup["PLAYER_STOP"] = PLAYER_STOP;
+    _lookup["EXTRA_OPTIONS"] = EXTRA_OPTIONS;
+    _lookup["HELP_URL"] = HELP_URL;
+    _lookup["INSTALL"] = INSTALL;
+    _lookup["UNINSTALL"] = UNINSTALL;
+    _lookup["START_VNC"] = START_VNC;
+    _lookup["ORDER"] = ORDER;
+    _lookup["SERVER"] = SERVER;
+    _lookup["HAS_CLIENT"] = HAS_CLIENT;
+    _lookup["CLIENT_LIST"] = CLIENT_LIST;
+    _lookup["MAC_ADDRESS"] = MAC_ADDRESS;
+    _lookup["REMOTE"] = REMOTE;
+    _lookup["ALSA_SETUP"] = ALSA_SETUP;
+    _lookup["WIZARD"] = WIZARD;
+    _lookup["CUSTOM_AUDIO"] = CUSTOM_AUDIO;
+    _lookup["GROUP"] = GROUP;
+    _lookup["INFO"] = INFO;
+  }
+}
+
+bool Players::getSetupConfig(const string &playerPath, SetupConfig &config)
+{
+  if (playerPath.empty())
+    return false;
+  if (!OS::exists(PATH_PLAYERS + playerPath + "/config"))
+    return false;
+  static Players p;
+
+  ifstream f(PATH_PLAYERS + playerPath + "/config", ios::in);
+  char buffer[2048];
+
+  if (f.good())
+  {
+    config.path = playerPath;
+    size_t pos = 0;
+
+    while (f.getline(buffer, 2047))
+    {
+      char ch = buffer[pos];
+      while (ch == ' ')
+        ch = buffer[++pos];
+
+      if (ch == '#')
+      {
+        continue; // skip comments
+      }
+      strings x;
+      utils::tokenise(buffer, x, '=');
+      if (x.size() == 2)
+      {
+        string &v = utils::unquote(x.back());
+        switch (p._lookup[x.front()])
+        {
+        case PLAYER_NAME:
+          config.name = v;
+          break;
+        case INIT:
+          config.init = v;
+          break;
+        case PROGRAM_FILE:
+          config.program = v;
+          break;
+        case MANUAL_CONFIG:
+          config.manual = v == "1" || v == "true";
+          break;
+        case CONFIG_FILE:
+          config.config = v;
+          break;
+        case PLAYER_START:
+          config.start = v;
+          break;
+        case PLAYER_STOP:
+          config.stop = v;
+          break;
+        case EXTRA_OPTIONS:
+          config.has_options = v == "1" || v == "true";
+          break;
+        case HELP_URL:
+          config.help = v;
+          break;
+        case INSTALL:
+          config.install = v;
+          break;
+        case UNINSTALL:
+          config.uninstall = v;
+          break;
+        case START_VNC:
+          config.vnc = stoi(v);
+          break;
+        case ORDER:
+          config.order = stoi(v);
+          break;
+        case SERVER:
+          config.server = stoi(v);
+          break;
+        case HAS_CLIENT:
+          config.has_client = v == "1" || v == "true";
+          break;
+        case CLIENT_LIST:
+          utils::tokenise(v, config.client_list, ';');
+          break;
+        case MAC_ADDRESS:
+          config.has_mac_adr = v == "1" || v == "true";
+          break;
+        case REMOTE:
+          config.remote = v;
+          break;
+        case ALSA_SETUP:
+          config.alsa_setup = v == "1" || v == "true";
+          break;
+        case WIZARD:
+          config.wizard = v == "1" || v == "true";
+          break;
+        case CUSTOM_AUDIO:
+          config.custom_audio = v == "1" || v == "true";
+          break;
+        case GROUP:
+          config.group = v;
+          break;
+        case INFO:
+          config.info = v;
+        default:
+          break;
+        }
+      }
+    }
+  }
+
+  f.close();
+
+  strings progs;
+  utils::tokenise(config.program, progs, ';');
+  config.installed = true;
+  
+  for (auto prog = progs.begin(); config.installed && prog != progs.end(); ++prog)
+  {
+    config.installed &= OS::exists(prog->find('/') == string::npos ? PATH_PLAYERS + playerPath + '/' + *prog
+                                                                   : *prog);
+  }
+
+  return !config.name.empty() && config.installed;
+}
+
+json::value Players::getPlayers(bool all)
+{
+  DIR *pDIR;
+  SetupConfigs player, server;
+
+  string player_server,
+      player_client;
+  if (all)
+  {
+    // Only used when all = true, else it will call itself on startup and blow up the heap
+    BackEnd *be = BackEnd::instance();
+    Config &cfg = be->config();
+  }
+  if ((pDIR = opendir(PATH_PLAYERS)))
+  {
+    struct dirent *entry;
+    while ((entry = readdir(pDIR)))
+    {
+      string path(entry->d_name);
+      if (path != "." && path != ".." && entry->d_type == DT_DIR)
+      {
+        SetupConfig cfg;
+        if (getSetupConfig(path, cfg) || all || OS::debug())
+        {
+          ((cfg.server | all) ? server : player).insert(make_pair(cfg.order, cfg));
+          if (cfg.server == 3)
+          {
+            player.insert(make_pair(cfg.order, cfg));
+          }
+        }
+      }
+    }
+    closedir(pDIR);
+  }
+
+  json::value v;
+
+  v["server"] = json::value::array(server.size());
+  v["client"] = json::value::array(player.size());
+
+  size_t c = 0;
+  for (auto it = player.begin(); it != player.end(); ++it, ++c)
+  {
+    json::value &vv = v["client"][c];
+    vv["name"] = json::value::string(U(it->second.name));
+    vv["path"] = json::value::string(U(it->second.path));
+    vv["vnc"] = json::value::boolean(it->second.vnc);
+    vv["manual"] = json::value::boolean(it->second.manual);
+    vv["alsa_setup"] = json::value::boolean(it->second.alsa_setup);
+    vv["wizard"] = json::value::boolean(it->second.wizard);
+    vv["custom_audio"] = json::value::boolean(it->second.custom_audio);
+    vv["group"] = json::value::string(U(it->second.group));
+    vv["info"] = json::value::string(U(it->second.info));
+
+    if (all)
+    {
+      vv["installed"] = json::value::boolean(it->second.installed);
+      vv["install"] = json::value::string(U(it->second.install));
+      vv["uninstall"] = json::value::string(U(it->second.uninstall));
+
+      vv["in_use"] = json::value::boolean(it->second.path == player_client || it->second.path == player_server);
+    }
+  }
+
+  c = 0;
+  for (auto it = server.begin(); it != server.end(); ++it, ++c)
+  {
+    json::value &vv = v["server"][c];
+    vv["name"] = json::value::string(U(it->second.name));
+    vv["path"] = json::value::string(U(it->second.path));
+    vv["vnc"] = json::value::boolean(it->second.vnc);
+    vv["manual"] = json::value::boolean(it->second.manual);
+    vv["has_client"] = json::value::boolean(it->second.has_client);
+    vv["client_list"] = Json(it->second.client_list).value();
+    vv["alsa_setup"] = json::value::boolean(it->second.alsa_setup);
+    vv["wizard"] = json::value::boolean(it->second.wizard);
+    vv["custom_audio"] = json::value::boolean(it->second.custom_audio);
+    vv["group"] = json::value::string(U(it->second.group));
+    vv["info"] = json::value::string(U(it->second.info));
+
+    if (all)
+    {
+      vv["installed"] = json::value::boolean(it->second.installed);
+      vv["install"] = json::value::string(U(it->second.install));
+      vv["uninstall"] = json::value::string(U(it->second.uninstall));
+      vv["in_use"] = json::value::boolean(it->second.path == player_server || it->second.path == player_client);
+    }
+  }
+
+  return v;
+}
+
+json::value Players::getConfig()
+{
+  Config &cfg = BackEnd::instance()->config();
+
+  json::value v; 
+
+  strings names;
+  json::value start, config;
+
+  cfg.getPlayersToStart(start);
+
+  cfg.getAllPlayersRuntimeConfig(config);
+
+  v["start"] = start;
+  v["config"] = config;
+
+  Features::getFeatures(v);
+
+  return v;
+}
+
+json::value Players::setConfig(const string &data)
+{
+  stop();
+  json::value obj = json::value::parse(data);
+
+  Config &cfg = BackEnd::instance()->config();
+
+  cfg.setPlayersToStart(obj["start"]);
+  cfg.setAllPlayersRuntimeConfig(obj["config"]);
+  string errMsg;
+  const int code = start(errMsg);
+
+  json::value v;
+  v["message"] = json::value::string(U(errMsg));
+  v["code"] = json::value::number(code);
+
+  return v;
+}
+
+void Players::stop()
+{
+  BackEnd * be = BackEnd::instance();
+  Config &cfg = be->config();
+
+  // get list of players
+  json::value players;
+  cfg.getPlayersToStart(players);
+
+  for (auto i = 0; i < players.size(); ++i) {
+    const string & playerName = players.at(i).as_string();
+    SetupConfig cfgSetup;
+    if (getSetupConfig(playerName, cfgSetup)) {
+      _stop(cfgSetup, be->getPlayerTask());
+    }
+  }
+}
+
+bool Players::start(string & errMsg)
+{
+  errMsg = "PLAYER.SAVED";
+
+  Config & cfg = BackEnd::instance()->config();
+  string env;
+
+  // get list of players
+  json::value players;
+  cfg.getPlayersToStart(players);
+  size_t idxAlsaCfg = 0;
+
+  for (auto i = 0; i < players.size(); ++i) {
+    const string & playerName = players.at(i).as_string();
+
+    SetupConfig cfgSetup;
+    if (!getSetupConfig(playerName, cfgSetup)) {
+      if (!cfgSetup.installed) {
+        continue;
+      }
+
+      errMsg = "PLAYER.ERROR.INVALID_CONFIG";
+      return true;
+    }
+
+    json::value cfgRuntime;
+    bool custom = false;
+
+    if (cfgSetup.alsa_setup) {
+      cfg.getPlayerRuntimeConfig(playerName, cfgRuntime);
+
+      if (!cfgRuntime.is_array()) {
+        cout << "Runtime config is not an array" << endl;
+        errMsg = "PLAYER.ERROR.INVALID_CONFIG";
+        return true;
+      }
+      const json::array & array = cfgRuntime.as_array();
+      idxAlsaCfg = array.size();
+      if (idxAlsaCfg == 0) {
+        cout << "There's no config";
+        errMsg = "PLAYER.ERROR.INVALID_CONFIG";
+        return true;
+      }
+
+      string options, name, output, format;
+      options = name = output = format = '"';
+      for (auto itConfig = array.cbegin(); itConfig != array.cend(); ++itConfig) {
+        const json::value & elem = *itConfig;
+    
+        if (itConfig == array.cbegin())
+        {
+          if (elem.has_field("custom") && elem.has_field("custom_config") && elem.at("custom").as_bool())
+          {
+            // cout << " ## Custom config" << endl;
+            string customCfg = elem.at("custom_config").as_string();
+            utils::replace(customCfg, "\"", "\\\"");
+
+            env = "_CUSTOM=\"" + customCfg + '\"';
+            custom = true;
+            break;
+          }
+          // cout << " ## Normal config" << endl;
+        } else {
+          options += '~';
+          name    += '~';
+          output  += '~';
+          format  += '~';
+        }
+    
+        //options += o["options"].as_string();
+        name    += elem.at("name").as_string();
+        output  += elem.at("output").as_string();
+        options += elem.at("options").as_string();
+        format  += elem.at("format").as_string();
+      }
+
+      name    += '"';
+      options += '"';
+      output  += '"';
+      format  += '"';
+
+      if (options == "\"\"\"\"") {
+        options="\"\"";
+      }
+    // cout << "   Name: " << name << endl
+    //      << " Output: " << output << endl
+    //      << "Options: " << options << endl
+    //      << " format: " << format << endl;
+
+      if (!custom) {
+        env = "_NAME=" + name +
+              " _OUTPUT=" + output +
+              " _FORMAT=" + format +
+              " _OPTIONS=\"" + options + "\"";
+      }
+    }
+
+    // cout << "@@@@: " << cfgSetup.name << endl;
+    _start(idxAlsaCfg, cfgSetup, env, BackEnd::instance()->getPlayerTask());
+  }
+  json::value v = BackEnd::instance()->config().getCpuConfig();
+  if (v[Config::CPUSET_SHIELD].as_bool())
+  {
+    snakeoil::startStopCpuset(true);
+  }
+
+  return false;
+}
+
+bool Players::_start(size_t numAudio, const SetupConfig &playerCfg, const string &env, shared_ptr<Task> task)
+{
+  task->code = 0;
+  task->done = false;
+
+  task->console.str("");
+  task->console.clear();
+  Time t;
+
+  task->console << "**** " << t.toString() << endl
+                << "**** " << playerCfg.name << endl
+                << endl;
+
+  ostringstream o;
+
+  o << "cd /var/www;";
+  if (!playerCfg.init.empty())
+  {
+    string mac;
+    if (playerCfg.has_mac_adr) {
+      BackEnd::instance()->config().getMacAddress(numAudio, mac);
+    }
+    o << env << ' ' << mac << ' ' << PATH_PLAYERS << playerCfg.path
+      << '/' << playerCfg.init
+      << ' ' << PATH_PLAYERS << playerCfg.path << " 2>&1;";
+  }
+
+  if (playerCfg.vnc)
+  {
+    task->console << "Starting VNC Server" << endl;
+    OS::saveTextFile("/var/www/config/player", playerCfg.path);
+    o << "/usr/bin/vncserver 2>&1;";
+  }
+  else
+  {
+    o << PATH_PLAYERS << playerCfg.path << '/' << playerCfg.start << ' '
+      << PATH_PLAYERS << playerCfg.path << " 2>&1;";
+  }
+
+  // task->console << "Command line: " << o.str() << endl;
+
+  OS::exec_nowait(o.str(), task);
+  // cout << "#####: " << task->console.str() << endl;
+  return 0;
+}
+
+bool Players::_stop(const SetupConfig &playerCfg, shared_ptr<Task> task)
+{
+  //task.reset();
+
+  ostringstream o;
+  if (playerCfg.vnc)
+  {
+    task->console << "Stopping VNC" << endl;
+    OS::exec_wait("/usr/bin/vncserver -kill :1 > /tmp/stdout 2> /tmp/stderr", task);
+  }
+
+  o << "cd /var/www;";
+  o << "bash \"" << PATH_PLAYERS << playerCfg.path << '/' << playerCfg.stop << '"';
+  task->console << "Executing: " << o.str() << endl;
+
+  return OS::exec_wait(o.str(), task);
+}
+
+const string Players::_getStatusAux(shared_ptr<Task> task, string &status, string &remote, string &errMsg, bool &error, bool &installed)
+{
+  BackEnd *be = BackEnd::instance();
+  SetupConfig playerCfg;
+  strings lines;
+
+  // Only check status if player is installed
+  if (getSetupConfig(status, playerCfg))
+  {
+    if (playerCfg.installed) {
+      if (!playerCfg.remote.empty())
+      {
+        if (OS::exec_wait(playerCfg.remote, remote)) {
+          cout << "Error: " << remote << endl;
+          remote = "{\"url\": \"\", \"name\": \"error\"}";
+        }
+      }
+
+      string::size_type n = playerCfg.program.rfind('/');
+      if (n != string::npos)
+        playerCfg.program = playerCfg.program.substr(n + 1);
+
+      OS::exec_wait("pgrep -x " + playerCfg.program + '*', lines);
+
+      if (lines.empty()) {
+        // if first pgrep turns out nothing, use a general search. 
+        string cmdline = "pgrep -f " + playerCfg.program + " | grep -i grep";
+        // take out mympd if program is MPD*
+        if (playerCfg.program.find("mpd") != string::npos)
+          cmdline += "|grep -i mympd";
+        OS::exec_wait(cmdline, lines);
+      }
+
+      if (lines.empty())
+      {
+        if (task)
+          errMsg = task->console.str();
+        status = "COMMON.ERROR";
+      }
+      else
+      {
+        // cout << "Lines: " << endl;
+        // copy(lines.begin(), lines.end(), ostream_iterator<string>(cout, "\n"));
+        // cout << " --------------" << endl;
+        ostringstream o;
+        o << be->translate("PLAYER.STATE.RUNNING") << " ("
+          << be->translate("PLAYER.STATE.PID") << ": ";
+        int c = 0;
+        for (auto it = lines.begin(); it != lines.end(); ++it, ++c)
+        {
+          if (c)
+            o << ", ";
+          o << *it;
+        }
+        o << ')';
+        status = o.str();
+      }
+    }
+
+    error = lines.empty();
+    installed = playerCfg.installed;
+    return playerCfg.name;
+  }
+  installed = false;
+  error = true;
+  return "";
+}
+
+void Players::_getPlayerNames(strings &names)
+{
+  json::value v = getPlayers(true);
+
+  json::value &s = v["server"];
+  const size_t n = s.size();
+  for (size_t idx = 0; idx < n; ++idx)
+  {
+    if (s[idx]["alsa_setup"].as_bool())
+      names.push_back(s[idx]["path"].as_string());
+  }
+}
+
+json::value Players::unmute()
+{
+  string msg;
+  OS::exec_wait("/usr/local/bin/alsa_unmute && alsactl store", msg);
+
+  Json v;
+
+  v.append("code", 0);
+  v.append("message", msg);
+
+  return v.value();
+}
+
+json::value Players::getStatus()
+{
+  BackEnd *be = BackEnd::instance();
+  Config &cfg = be->config();
+
+  // get list of players
+  json::value players;
+  cfg.getPlayersToStart(players);
+  strings remotes;
+
+  json::value v;
+  v["players"] = json::value::array(players.size());
+
+  for (auto i = 0, j = 0; i < players.size(); ++i, ++j) {
+    json::value & elem = v["players"].at(i);
+    string status = players.at(i).as_string(), 
+          remote, errMsg;
+    bool err, installed;
+
+    elem["name"] = json::value::string(U(_getStatusAux(be->getPlayerTask(), status, remote, errMsg, err, installed)));
+    elem["installed"] = json::value::boolean(installed);
+    elem["error"] = json::value::boolean(err);
+    elem["status"] = json::value::string(U(status));
+    elem["message"] = json::value::string(U(errMsg));
+    if (!remote.empty()) {
+      elem["remote"] = json::value::parse(remote);
+    }
+  }
+
+  return v;
+}
+
+json::value Players::getBasicMode() {
+  json::value v;
+  Config &cfg = BackEnd::instance()->config();
+  v["basic_mode"] = json::value::boolean(cfg.getPlayerBasicMode());
+
+  return v;
+}
+
+json::value Players::setBasicMode(const string & data) {
+  json::value v = json::value::parse(data);
+  Config &cfg = BackEnd::instance()->config();
+  cfg.setPlayerBasicMode(v["basic_mode"].as_bool());
+  return v;
+}
diff --git a/API/src/snakeoil.cpp b/API/src/snakeoil.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fee0d4250f2bd4b212c5e81e7e90f908891b5f81
--- /dev/null
+++ b/API/src/snakeoil.cpp
@@ -0,0 +1,854 @@
+#include "snakeoil.hpp"
+#include "BackEnd.hpp"
+#include "task.hpp"
+#include "os.hpp"
+#include "audio.hpp"
+#include "players.hpp"
+#include "utils.hpp"
+#include "features.hpp"
+#include <snakeoil/activate.h>
+
+
+#include <unistd.h>
+#include <algorithm>
+#include <sstream>
+#include <chrono>
+#include <iomanip>
+
+
+using namespace std;
+using namespace chrono;
+using namespace web;
+
+
+namespace snakeoil
+{
+bool parseActivationDetails(const string &name, const string &mail, const string &code, string &msg)
+{
+  if (name.empty())
+  {
+    msg = "SNAKEOIL.ACTIVATION_NAME_EMPTY";
+    return 1;
+  }
+  if (mail.empty())
+  {
+    msg = "SNAKEOIL.ACTIVATION_MAIL_EMPTY";
+    return 1;
+  }
+  if (code.empty())
+  {
+    msg = "SNAKEOIL.ACTIVATION_CODE_EMPTY";
+    return 1;
+  }
+
+  bool rtn;
+
+  Snakeoil::Activate activate(name, mail, code);
+
+  if ((rtn = activate.isActivated()))
+  {
+    msg = "SNAKEOIL.ACTIVATION_SUCCESS";
+    Config &cfg = BackEnd::instance()->config();
+    cfg.setRegoName(name);
+    cfg.setRegoMail(mail);
+    cfg.setRegoCode(code);
+
+    // Start anything that requires activation
+    audio::startRavennaClient();
+  }
+  else
+  {
+    msg = "SNAKEOIL.ACTIVATION_FAILURE";
+  }
+
+  return rtn == 0;
+}
+
+json::value getSoftware(const string &data){
+  json::value v;
+  BackEnd *be = BackEnd::instance();
+  Config &cfg = be->config();
+  
+  if (cfg.isActivated())
+  {
+    auto t = be->getSnakeoilTask();
+
+    if (t->userFlag)
+    {
+      json::value d = json::value::parse(data);
+      if (d.has_field("done"))
+      {
+        t->userFlag = false;
+      }
+      else
+      {
+        // still in the midst of installing, uninstalling.
+        v["console"] = json::value::string(U(t->console.str()));
+        v["done"] = json::value::boolean(t->done);
+      }
+    }
+
+    Features::getFeatures(v);
+
+    v["players"] = Players::getPlayers(true);
+  }
+
+  return v;
+}
+
+json::value getServices(const string & data)
+{
+  json::value v;
+  BackEnd *be = BackEnd::instance();
+  Config &cfg = be->config();
+
+  if (cfg.isActivated())
+  {
+    int idx = 0;
+    v["services"] = json::value::array(4);
+    v["services"][idx]["name"] = json::value::string("ssh");
+    v["services"][idx]["tooltip"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.SSH_HELP");
+    v["services"][idx]["description"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.SSH");
+    v["services"][idx]["enabled"] = json::value::boolean(cfg.getServiceSSH());
+
+    v["services"][++idx]["name"] = json::value::string("console");
+    v["services"][idx]["tooltip"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.CONSOLE_HELP");
+    v["services"][idx]["description"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.CONSOLE");
+    v["services"][idx]["enabled"] = json::value::boolean(cfg.getServiceConsole());
+
+    v["services"][++idx]["name"] = json::value::string("samba");
+    v["services"][idx]["tooltip"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.SAMBA_HELP");
+    v["services"][idx]["description"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.SAMBA");
+    v["services"][idx]["enabled"] = json::value::boolean(cfg.getServiceSamba());
+
+    // v["service"][++idx]["name"] = json::value::string("monitor");
+    // v["service"][idx]["desciption"] = json::value::string();
+    // v["service"][idx]["enabled"] = json::value::boolean(cfg.getServiceSSH());
+
+    v["services"][++idx]["name"] = json::value::string("avahi");
+    v["services"][idx]["tooltip"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.AVAHI_HELP");
+    v["services"][idx]["description"] = json::value::string("SNAKEOIL.MANAGE_SERVICES.AVAHI");
+    v["services"][idx]["enabled"] = json::value::boolean(cfg.getServiceAvaHi());
+  }
+
+  return v;
+}
+
+json::value getKernel(const string & data)
+{
+  json::value v;
+  Config & cfg = BackEnd::instance()->config();
+
+  if (cfg.isActivated())
+  {
+    v["kernel"]["boot"] = json::value::string(U(OS::getBootKernel()));
+    v["kernel"]["grub"] = json::value::string(U(OS::getGrubKernel()));
+    v["kernel"]["clocksource"] = json::value::string(U(OS::getClocksource()));
+    v["kernel"]["options"] = json::value::string(U(OS::getKernelOptions()));
+
+    v["system"]["clocksources"] = OS::getAvailClocksource();
+    v["system"]["options"] = OS::getAvailKernelOptions();
+    v["system"]["kernels"] = OS::getAvailBootKernels();
+  }
+
+  return v;
+}
+
+json::value getHardware(const string & data)
+{
+  json::value v;
+  Config &cfg = BackEnd::instance()->config();
+
+  if (cfg.isActivated())
+  {
+
+    v["process"] = cfg.getProcPrio();
+    v["cpu"] = cfg.getCpuConfig();
+    v["ramdisk"] = cfg.getRamdiskConfig();
+    v["uhubctl"] = json::value::boolean(cfg.getUHubCtlEnabled());
+
+    Features::getFeatures(v);
+  }
+
+  return v;
+}
+
+/*
+json::value getConfig(const string &data)
+{
+  json::value v;
+  BackEnd *be = BackEnd::instance();
+  Config &cfg = be->config();
+
+  if (cfg.isActivated())
+  {
+    auto t = be->getSnakeoilTask();
+
+    if (t->userFlag)
+    {
+      json::value d = json::value::parse(data);
+      if (d.has_field("done"))
+      {
+        t->userFlag = false;
+      }
+      else
+      {
+        // still in the midst of installing, uninstalling.
+        v["console"] = json::value::string(U(t->console.str()));
+        v["done"] = json::value::boolean(t->done);
+      }
+    }
+
+    v["service"]["ssh"] = json::value::boolean(cfg.getServiceSSH());
+    v["service"]["console"] = json::value::boolean(cfg.getServiceConsole());
+    v["service"]["samba"] = json::value::boolean(cfg.getServiceSamba());
+    v["service"]["monitor"] = json::value::boolean(cfg.getServiceStorageMonitor());
+    v["service"]["avahi"] = json::value::boolean(cfg.getServiceAvaHi());
+
+    v["kernel"]["boot"] = json::value::string(U(OS::getBootKernel()));
+    v["kernel"]["grub"] = json::value::string(U(OS::getGrubKernel()));
+    v["kernel"]["clocksource"] = json::value::string(U(OS::getClocksource()));
+    v["kernel"]["options"] = json::value::string(U(OS::getKernelOptions()));
+
+    v["process"] = cfg.getProcPrio();
+    v["cpu"] = cfg.getCpuConfig();
+    v["ramdisk"] = cfg.getRamdiskConfig();
+
+    v["players"] = Players::getPlayers(true);
+
+
+    v["dsd"] = audio::getDsdConfig(data);
+
+    v["uhubctl"] = json::value::boolean(cfg.getUHubCtlEnabled());
+
+    Features::getFeatures(v);
+  }
+
+  return v;
+}
+*/
+json::value getUSBPorts(const string &)
+{
+  json::value v;
+  v["usb"] = OS::getUSBPorts();
+
+  return v;
+}
+
+json::value postSoftware(const string &data)
+{
+  // assigned to and read by multiple tasks.
+  // By using a shared pointer, these objects outlives
+  // the tasks, which can run in the background after
+  // this function exits.
+  auto be = make_shared<BackEnd *>(BackEnd::instance());
+  auto cfg = make_shared<Config *>(&(*be)->config());
+  auto obj = make_shared<json::value>(json::value::parse(data));
+
+  int updated = NO_CHANGES;
+  int code = 0; 
+  json::value v;
+  string errMsg;
+  
+  if ((*cfg)->isActivated())
+  {
+    json::value p = Players::getPlayers(true);
+    json::value &software = p["server"];
+    json::value &settings = (*obj)["players"];
+
+    // convert above to a searchable DS
+    typedef struct __Config
+    {
+      bool installed;
+      const char *name;
+      const char *install;
+      const char *uninstall;
+      __Config(bool a, const char *n, const char *i, const char *u)
+      {
+        installed = a;
+        name = n;
+        install = i;
+        uninstall = u;
+      }
+    } __Config;
+
+    map<string, __Config> status; // patch -> installed or not, name
+    size_t sz = software.size();
+    for (size_t idx = 0; idx < sz; ++idx)
+    {
+      json::value &i = software[idx];
+
+      if (i["install"].as_string().empty() && i["uninstall"].as_string().empty())
+        continue;
+      status.insert(make_pair(i["path"].as_string(), __Config(i["installed"].as_bool(),
+                                                              i["name"].as_string().c_str(),
+                                                              i["install"].as_string().c_str(),
+                                                              i["uninstall"].as_string().c_str())));
+    }
+
+    map<string, pair<bool, string>> cmds; // path -> (un)install command
+
+    // now iterate through player settings changes
+    sz = settings.size();
+    for (size_t idx = 0; idx < sz; ++idx)
+    {
+      const string &path = settings[idx]["path"].as_string();
+
+      auto it = status.find(path);
+      if (it == status.end())
+        continue;
+
+      bool action = settings[idx]["installed"].as_bool();
+      auto c = it->second;
+      if (action != c.installed)
+      {
+        string cmd = Players::PATH_PLAYERS + path + '/';
+        cmd += (action ? c.install : c.uninstall);
+        cmds.insert(make_pair(path, make_pair(action, cmd)));
+      }
+    }
+
+    // check Ubuntu software - install exfat
+    if (Features::hasFSExFat() && !(*obj)["ubuntu"]["exfat"].as_bool())
+    {
+      updated |= SOFTWARE;
+      cmds.insert(make_pair("exfat", make_pair(false, "apt-get purge -y exfat-utils exfat-fuse")));
+    }
+    else if (!Features::hasFSExFat() && (*obj)["ubuntu"]["exfat"].as_bool())
+    {
+      updated |= SOFTWARE;
+      cmds.insert(make_pair("exfat", make_pair(true, "apt-get install -y exfat-utils exfat-fuse")));
+    }
+
+    // check Ubuntu software - install cputset
+    if (Features::hasCPUSet() && !(*obj)["ubuntu"]["cpuset"].as_bool())
+    {
+      updated |= SOFTWARE;
+      cmds.insert(make_pair("cpuset", make_pair(false, "apt-get purge -y cpuset")));
+    }
+    else if (!Features::hasCPUSet() && (*obj)["ubuntu"]["cpuset"].as_bool())
+    {
+      updated |= SOFTWARE;
+      cmds.insert(make_pair("cpuset", make_pair(true, "apt-get install -y cpuset")));
+    }
+
+    // check Ubuntu software - install ecasound
+    if (Features::hasEcaSound() && !(*obj)["ubuntu"]["ecasound"].as_bool())
+    {
+      updated |= SOFTWARE;
+      cmds.insert(make_pair("ecasound", make_pair(false, "apt-get purge -y ecasound")));
+    }
+    else if (!Features::hasEcaSound() && (*obj)["ubuntu"]["ecasound"].as_bool())
+    {
+      updated |= SOFTWARE;
+      cmds.insert(make_pair("ecasound", make_pair(true, "apt-get install -y ecasound")));
+    }
+
+    // execute all the commands in the list
+    if (!cmds.empty())
+    { 
+      updated |= SOFTWARE;
+      auto task = (*be)->getSnakeoilTask();
+
+      task->code = 0;
+      task->done = false;
+      if (!task->userFlag)
+      {
+        task->console.str("");
+        task->console.str().clear(); 
+      }
+
+      auto t = pplx::create_task([cmds, task, be]() -> int {
+        task->userFlag = true;
+
+        OS::exec_wait("apt-get update", task);
+        task->console << (*be)->translate("UPDATE.SOFTWARE.BEGIN") << endl;
+        for (auto it = cmds.begin(); it != cmds.end(); ++it)
+        {
+          task->console << "*** " << (*be)->translate("UPDATE.SOFTWARE.NAME") << ": " << it->first << ' '
+                        << (*be)->translate("UPDATE.SOFTWARE.MODE") << ": "
+                        << (*be)->translate((it->second.first ? "UPDATE.SOFTWARE.INSTALL"
+                                                              : "UPDATE.SOFTWARE.UNINSTALL"))
+                        << " ***" << endl;
+
+          if (it->second.second.find("apt-get") == 0)
+            OS::exec_wait(it->second.second, task);
+          else
+            OS::exec_wait("bash " + it->second.second, task);
+        }
+        task->console << endl
+                      << (*be)->translate((task->code? "UPDATE.UPDATE_ERROR"
+                                                     : "UPDATE.UPDATE_COMPLETE")) << endl;
+        task->done = true;
+
+        return task->code;
+      });
+    }
+  }
+
+  if (updated & SOFTWARE)
+  {
+    auto task = (*be)->getSnakeoilTask();
+    v["console"] = json::value::string(U(task->console.str()));
+  }
+
+  v["code"] = json::value::number(code);
+  return v;
+}
+
+json::value postServices(const string & data)
+{
+  // Create a shared pointer to a string that is
+  // assigned to and read by multiple tasks.
+  // By using a shared pointer, these objects outlives
+  // the tasks, which can run in the background after
+  // this function exits.
+  auto be = make_shared<BackEnd *>(BackEnd::instance());
+  auto cfg = make_shared<Config *>(&(*be)->config());
+  auto obj = make_shared<json::value>(json::value::parse(data));
+
+  int updated = NO_CHANGES;
+  int code = 0;
+  json::value v;
+  string errMsg;
+
+  if ((*cfg)->isActivated())
+  {
+    json::array & services = (*obj)["services"].as_array();
+
+    // XXX_TJ: Need to clean this up. Less hardcoding, more generic
+    for (auto it = services.cbegin(); it != services.cend(); ++it) {
+      const string & name = it->at("name").as_string();
+      if (name == "ssh") {
+        (*cfg)->setServiceSSH(it->at("enabled").as_bool());
+      } else if (name == "console") {
+        (*cfg)->setServiceConsole(it->at("enabled").as_bool());
+      } else if (name == "samba") {
+        (*cfg)->setServiceSamba(it->at("enabled").as_bool());
+      } else if (name == "avahi") {
+        (*cfg)->setServiceAvaHi(it->at("enabled").as_bool());
+      } else {
+        code = 1;
+      }
+    }
+
+    auto t2 = pplx::create_task([]() -> void {
+      startStopServices();
+    });
+  } else {
+    code = 1;
+  }
+
+  v["code"] = json::value::number(code);
+
+  return v;
+}
+
+json::value postKernel(const string & data)
+{
+  // assigned to and read by multiple tasks.
+  // By using a shared pointer, these objects outlives
+  // the tasks, which can run in the background after
+  // this function exits.
+  auto be = make_shared<BackEnd *>(BackEnd::instance());
+  auto cfg = make_shared<Config *>(&(*be)->config());
+  auto obj = make_shared<json::value>(json::value::parse(data));
+  int updated = NO_CHANGES;
+  int code = 0;
+  string errMsg;
+  json::value v;
+
+  if ((*cfg)->isActivated())
+  {
+    // check kernel stuffs
+    const string &boot = (*obj)["kernel"]["boot"].as_string();
+    const string &clock = (*obj)["kernel"]["clocksource"].as_string();
+    const string &opts = (*obj)["kernel"]["options"].as_string();
+
+    if (!OS::exists("/var/www/config/grub.template"))
+    {
+      errMsg = "SNAKEOIL.KERNEL.GRUB_TEMPLATE_MISSING";
+      code = 501;
+    }
+    else if (!(boot == OS::getBootKernel() &&
+              clock == OS::getClocksource() &&
+               opts == OS::getKernelOptions()))
+    {
+      updated |= KERNEL | REBOOT_REQUIRED;
+
+      auto tGrub = pplx::create_task([clock, boot, opts]() -> void {
+        //cout << clock << ' ' << boot << ' ' << opts << endl;
+
+        // call kernel update function
+        if (OS::getArch() == "armv7l")
+        {
+          OS::exec_nowait("sed -i \"s/\\(.*\\)kernel=.*\\(.*\\)/\\1kernel=kernel-"
+                            + boot + "\\2/g\" /boot/config.txt");
+          /*cout << "cmd: " << "sed \"s/\\(.*\\)kernel=.*\\(.*\\)/\\1kernel=kernel-"
+                            + boot + "\\2/g\" /boot/config.txt" << endl; */
+        }
+        else
+        {
+          OS::exec_nowait("sed -e \"s/@NEW_CLOCKSOURCE@/" + clock + "/g\" "
+                          "-e \"s/@NEW_VERSION@/" + boot + "/g\" " "-e \"s/@NEW_OPTIONS@/" +
+                          (opts == "none" ? "" : opts) + "/g\" "
+                          "/var/www/config/grub.template > /etc/default/grub && update-grub");
+        }
+      });
+    }
+  } else {
+    code = 1;
+  }
+  if (errMsg.empty()) {
+    v["message"] = json::value::string(U(updated ? (updated & REBOOT_REQUIRED) ? "SNAKEOIL.SAVED_REBOOT"
+                                                                               : "SNAKEOIL.SAVED"
+                                                 : "SNAKEOIL.NOT_SAVED"));
+  } else {
+    v["message"] = json::value::string(errMsg);
+  }
+
+  v["code"] = json::value::number(code);
+
+  return v;
+}
+
+json::value postHardware(const string & data)
+{
+  auto be = make_shared<BackEnd *>(BackEnd::instance());
+  auto cfg = make_shared<Config *>(&(*be)->config());
+  auto obj = make_shared<json::value>(json::value::parse(data));
+  int updated = NO_CHANGES;
+  int code = 0;
+  string errMsg;
+  json::value v;
+
+  if ((*cfg)->isActivated())
+  {
+    const  bool uhubctl = (*obj)["uhubctl"].as_bool();
+
+    if ((*cfg)->setProcPrio((*obj)["process"]))
+    {
+      updated |= PROCESS;
+      auto tPRIO = pplx::create_task([cfg]() -> void { chprio(); });
+    }
+
+    if ((*cfg)->setRamdiskConfig((*obj)["ramdisk"]))
+    {
+      updated |= RAMDISK;
+    }
+
+    if ((*cfg)->getUHubCtlEnabled() != uhubctl) {
+      // cout << "Change use uhubctl to: " << uhubctl << endl;
+      (*cfg)->setUHubCtlEnabled(uhubctl);
+      updated |= USB;
+    }
+
+    // Check if USB strings needs to be changed
+    ostringstream newUSB;
+    for (size_t i = 0; i < (*obj)["usb"].size(); ++i)
+    {
+      if (!(*obj)["usb"][i]["power"].as_bool())
+      {
+        if (!newUSB.str().empty())
+          newUSB << ';';
+        newUSB << (*obj)["usb"][i]["vendor"].as_string() << '#' << (*obj)["usb"][i]["port"].as_integer();
+      }
+    }
+    string origUSB;
+    (*cfg)->getUsbOff(origUSB);
+
+    if (origUSB != newUSB.str())
+    {
+      updated |= USB;
+      auto tUSB = pplx::create_task([cfg, obj]() -> void {
+        string off;
+        if (OS::setUSBPorts((*obj)["usb"], off))
+        {
+          (*cfg)->setUsbOff(off);
+        }
+      });
+    }
+    // now check CPUSetShield
+    if (Features::hasCGroup())
+    {
+      (*cfg)->setCpuConfig((*obj)["cpu"]);
+
+      startStopCpuset((*cfg)->getCpuConfig()[Config::CPUSET_SHIELD].as_bool());
+    }
+  } else {
+    code = 1;
+  }
+
+  v["code"] = json::value::number(code);
+
+  return v;
+}
+
+void chprio(int seconds)
+{
+  auto t = pplx::create_task([seconds]() -> void {
+    BackEnd *be = BackEnd::instance();
+    Config &cfg = be->config();
+
+    if (cfg.isActivated())
+    {
+      if (seconds > 0)
+      {
+        for (int i = 0; i < seconds; ++i)
+        {
+          if (!be->isRunning())
+            return;
+          sleep(1);
+        }
+      }
+
+      json::value v = cfg.getProcPrio();
+
+      for (size_t i = 0; i < v.size(); ++i)
+      {
+        ostringstream o;
+        string msg;
+        string program;
+
+        OS::exec_wait("pgrep " + v[i]["name"].as_string() + " 2>&1", program);
+
+        if (!program.empty())
+        {
+          o << "/usr/bin/chrt -a -p " << v[i]["priority"].as_string()
+            << ' ' << program << " 2>&1";
+          OS::exec_wait(o.str(), msg);
+        }
+      }
+    }
+  });
+}
+
+void powerOffUsb()
+{
+  Config &cfg = BackEnd::instance()->config();
+  string d;
+  strings t;
+  cfg.getUsbOff(d);
+  utils::tokenise(d, t, ';');
+  map<string, map< string, string> > off;
+  for (auto it = t.begin(); it != t.end(); ++it)
+  {
+    strings v;
+    utils::tokenise(*it, v, ',');
+    if (v.size() == 3)
+    {
+      if (!off[v[0]][v[1]].empty())
+        off[v[0]][v[1]] += ',';
+      off[v[0]][v[1]] += v[2];
+    }
+  }
+
+  for (auto it = off.begin(); it != off.end(); ++it)
+  {
+    for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
+    {
+      string msg;
+      //cout << "#: uhubctl -l " + it->first + " -n " + it2->first + " -p " + it2->second + " -a 0 -e"<<endl;
+      OS::exec_wait("uhubctl -l " + it->first + " -n " + it2->first + " -p " + it2->second + " -a 0 -e", msg);
+    }
+  }
+}
+
+void startStopServices(bool x)
+{
+  Config &cfg = BackEnd::instance()->config();
+
+  if (cfg.isActivated())
+  {
+    startStopSSH(cfg.getServiceSSH());
+    startStopCON(cfg.getServiceConsole());
+    startStopSMB(cfg.getServiceSamba());
+    startStopAVA(cfg.getServiceAvaHi());
+    if (x)
+      startStopCpuset(cfg.getCpuConfig()[Config::CPUSET_SHIELD].as_bool());
+  }
+  else
+  {
+    startStopSSH(true);
+    startStopSMB(true);
+    startStopCON(true);
+    startStopAVA(true);
+  }
+}
+
+void startStopSSH(bool start)
+{
+  const string cmd = (start ? "restart" : "stop");
+  string msg;
+  OS::exec_wait("/etc/init.d/ssh " + cmd, msg);
+}
+
+void startStopSMB(bool start)
+{
+  const string cmd = (start ? "restart" : "stop");
+  string msg;
+  OS::exec_wait("/etc/init.d/samba " + cmd + " >/dev/null 2> /dev/null", msg);
+}
+
+void startStopCON(bool start)
+{
+  int num = start;
+
+  ostringstream o;
+  o << "[Login]" << endl
+    << "NAutoVTs=" << num << endl
+    << "ReserveVT=" << num << endl;
+
+  OS::saveTextFile("/etc/systemd/logind.conf", o.str());
+}
+
+void startStopAVA(bool start)
+{
+  string msg;
+  if (start)
+  {
+    OS::exec_wait("systemctl enable  avahi-daemon >/dev/null 2> /dev/null;"
+                  "systemctl restart avahi-daemon >/dev/null 2> /dev/null",
+                  msg);
+  }
+  else
+  {
+    OS::exec_wait("systemctl disable avahi-daemon >/dev/null 2> /dev/null;"
+                  "systemctl stop avahi-daemon    >/dev/null 2> /dev/null",
+                  msg);
+  }
+}
+
+void startStopCpuset(bool start)
+{
+  if (!Features::hasCGroup())
+    return;
+
+  Config &cfg = BackEnd::instance()->config();
+
+  json::value v = cfg.getCpuConfig();
+  if (cfg.isActivated())
+  {
+    ostringstream cmd;
+
+    cmd << "#!/bin/bash" << endl << endl;
+
+    if (start)
+    {
+      // Build CSet commands
+      cmd << "cset shield --cpu ";
+      int count = 0;
+      for (size_t idx = 0; idx < v[Config::CPUSET_CONFIG].size(); ++idx)
+      {
+        if (v[Config::CPUSET_CONFIG][idx]["user"].as_bool())
+        {
+          if (count)
+            cmd << ',';
+          cmd << v[Config::CPUSET_CONFIG][idx]["core"].as_integer();
+          ++count;
+        }
+      }
+      cmd << " --kthread=on" << endl;
+
+      // get list of players
+      json::value players;
+      cfg.getPlayersToStart(players);
+      
+      for (auto i = 0; i < players.size(); ++i) {
+        const string & playerName = players.at(i).as_string();
+        SetupConfig cfgSetup;
+
+        if (Players::getSetupConfig(playerName, cfgSetup)) {
+          cout << "playerName: " << playerName << endl
+               << "      Path: " << cfgSetup.path << endl;
+
+          cmd << "PROGRAM_FILE_" << i << "=$(grep PROGRAM_FILE " << Players::PATH_PLAYERS << playerName
+              << "/config |sed \"s/.*PROGRAM_FILE=\\\"\\(.*\\)\\\".*/\\1/g\")" << endl
+              << "BASE=$(basename ${PROGRAM_FILE_" << i << "})" << endl
+              << "COUNT=0" << endl
+              << "while [ -z ${SNAKEOIL_PID_" << i << "} ]; do " << endl
+              //<< "  echo \"COUNT: ${COUNT} = ${BASE} = ${S_SNAKEOIL_PID}\"" << endl
+              << "  SNAKEOIL_PID_" << i << "=$(pgrep -x ${BASE})" << endl
+              << "  if [ ${COUNT} -gt 20 ]; then" << endl
+              << "    break" << endl
+              << "  elif [ ${COUNT} -gt 2 ]; then" << endl
+              << "    sleep 0.5" << endl
+              << "  fi" << endl
+              << "  COUNT=$((COUNT+1))" << endl
+              << "done" << endl
+              << endl
+              << "if [ -z ${SNAKEOIL_PID_"<< i << "} ]; then" << endl
+              << "  SNAKEOIL_PID_" << i << "=$(pgrep -d, -f .*$PROGRAM_FILE_" << i << ".*)" << endl
+              << "fi" << endl
+          
+              << "if [ -n ${SNAKEOIL_PID_" << i << "} ]; then " << endl
+              << "  cset proc --move --pid=${SNAKEOIL_PID_" << i << "} --threads --toset=user --force &" << endl
+              << "fi" << endl << endl;
+        }
+      }
+
+      // now find the players, and move 'em
+      // if (useServer && startServer)
+      // {
+      //   cmd << "S_PROGRAM_FILE=$(grep PROGRAM_FILE " << Players::PATH_PLAYERS << cfgServer.path
+      //       << "/config |sed \"s/.*PROGRAM_FILE=\\\"\\(.*\\)\\\".*/\\1/g\")" << endl
+      //       << "BASE=$(basename ${S_PROGRAM_FILE})" << endl
+      //       << "COUNT=0" << endl
+      //       << "while [ -z ${S_SNAKEOIL_PID} ]; do " << endl
+      //       //<< "  echo \"COUNT: ${COUNT} = ${BASE} = ${S_SNAKEOIL_PID}\"" << endl
+      //       << "  S_SNAKEOIL_PID=$(pgrep -x ${BASE})" << endl
+      //       << "  if [ ${COUNT} -gt 20 ]; then" << endl
+      //       << "    break" << endl
+      //       << "  elif [ ${COUNT} -gt 2 ]; then" << endl
+      //       << "    sleep 0.5" << endl
+      //       << "  fi" << endl
+      //       << "  COUNT=$((COUNT+1))" << endl
+      //       << "done" << endl
+      //       << endl
+      //       << "if [ -z ${S_SNAKEOIL_PID} ]; then" << endl
+      //       << "  S_SNAKEOIL_PID=$(pgrep -d, -f .*$S_PROGRAM_FILE.*)" << endl
+      //       << "fi" << endl
+      // 
+      //       << "if [ -n ${S_SNAKEOIL_PID} ]; then " << endl
+      //       << "  cset proc --move --pid=${S_SNAKEOIL_PID} --threads --toset=user --force &" << endl
+      //       << "fi" << endl << endl;
+      // }
+      // 
+      // if (startClient && Players::getSetupConfig(client, cfgClient))
+      // {
+      //   cmd << "C_PROGRAM_FILE=$(grep PROGRAM_FILE " << Players::PATH_PLAYERS << cfgClient.path
+      //       << "/config |sed \"s/.*PROGRAM_FILE=\\\"\\(.*\\)\\\".*/\\1/g\")" << endl
+      //       << "BASE=$(basename ${C_PROGRAM_FILE})" << endl
+      //       << "COUNT=0" << endl
+      //       << "while [ -z ${C_SNAKEOIL_PID} ]; do " << endl
+      //       << "  C_SNAKEOIL_PID=$(pgrep -x ${BASE})" << endl
+      //       //<< "  echo \"CLIENT COUNT: ${COUNT} = ${BASE} = ${C_SNAKEOIL_PID}\"" << endl
+      //       << "  if [ ${COUNT} -gt 20 ]; then" << endl
+      //       << "    break" << endl
+      //       << "  elif [ ${COUNT} -gt 2 ]; then" << endl
+      //       << "    sleep 0.5" << endl
+      //       << "  fi" << endl
+      //       << "  COUNT=$((COUNT+1))" << endl
+      //       << "done" << endl
+      //       << endl
+      //       << "if [ -z ${C_SNAKEOIL_PID} ]; then " << endl
+      //       << "  C_SNAKEOIL_PID=$(pgrep -d, -f .*$C_PROGRAM_FILE.*)" << endl
+      //       << "fi" << endl
+      //       //<< "  echo \"CLIENT COUNT: ${COUNT} = ${BASE} = ${C_SNAKEOIL_PID}\"" << endl
+      //       << "if [ -n ${C_SNAKEOIL_PID} ]; then" << endl
+      //       //<< "  echo \"##### movinig client\"" << endl
+      //       << "  cset proc --move --pid=${C_SNAKEOIL_PID} --threads --toset=user --force &" << endl
+      //       << "fi" << endl;
+      // }
+    }
+    else
+    {
+      cmd << "cset shield -r -f" << endl;
+    }
+
+    // now run everything.
+    OS::saveTextFile("/var/tmp/shield.sh", cmd.str());
+    OS::exec_nowait("sh /var/tmp/shield.sh; rm -f /var/tmp/shield.sh");
+  }
+}
+} // namespace snakeoil
diff --git a/API/src/snakesys.cpp b/API/src/snakesys.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..61d799e9f78ee009664fb93a2e8897a40d447999
--- /dev/null
+++ b/API/src/snakesys.cpp
@@ -0,0 +1,900 @@
+#include "snakesys.hpp"
+#include "BackEnd.hpp"
+#include "players.hpp"
+#include "utils.hpp"
+#include "os.hpp"
+#include "task.hpp"
+#include "time.hpp"
+
+#include <dirent.h>
+#include <iomanip>
+#include <algorithm>
+#include <fstream>
+#include <memory>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <b64/decode.h>
+
+using namespace std;
+using namespace web;
+
+typedef map<string, string> TranslateItems;
+
+void parseLanguageElements(const json::object &obj, const string &node, TranslateItems &ti);
+void prettyPrint(ostringstream &o, const json::value &v, int step = 0);
+
+namespace snakesys
+{
+string getSnakeoilUser()
+{
+  string x;
+  OS::exec_wait("grep :1000 /etc/passwd| awk -F: '{print $1}'|sed -e \"s/^[[:space:]]*//g\"", x);
+
+  return x;
+}
+
+json::value shutdown()
+{
+  string m;
+  OS::exec_nowait("sleep 2 && shutdown -h now", "Shutdown", m);
+  Json v;
+  v.append("code", 0);
+  v.append("message", "SYSTEM.SHUTDOWN");
+
+  return v.value();
+}
+
+json::value reset()
+{
+  string m;
+  OS::exec_nowait("sleep 2 && reboot -f", "Reset", m);
+
+  Json v;
+  v.append("code", 0);
+  v.append("message", "SYSTEM.RESET");
+
+  return v.value();
+}
+
+json::value clearCache()
+{
+  string x, y, z;
+  OS::exec_wait("free", y);
+  OS::exec_wait("echo 3 > /proc/sys/vm/drop_caches && /bin/sync", x);
+  OS::exec_wait("free", z);
+
+  Json v;
+  v.append("code", 0);
+  v.append("message", "SYSTEM.CLEAR_CACHE");
+
+  return v.value();
+}
+
+web::json::value getSystemDiagnostics(const string &diagFile)
+{
+  stringstream o;
+  o << "pwd;"
+       "SO_TEMP=`mktemp -d`;"
+       "DIAG=$SO_TEMP/`hostname`;"
+       "mkdir $DIAG;"
+       "rm -rf /var/www/config/diag.tar.bz2;"
+       "cp --parents /etc/default/grub  $DIAG;"
+       "cp --parents /var/www/config -r $DIAG;"
+       "dpkg -l > $DIAG/installed.packages;"
+       "netstat -tulpn > $DIAG/netstat;"
+       "ps aux > $DIAG/processes;"
+       "cp -f /tmp/stdout $DIAG/stdout 2> /dev/null;"
+       "cp -f /tmp/stderr $DIAG/stderr 2> /dev/null;"
+       "cp -f /etc/lighttpd/lighttpd.conf $DIAG/lighttpd.conf 2> /dev/null;"
+       "cp -f /var/tmp/stdout $DIAG/stdout2 2> /dev/null;"
+       "cp -f /var/tmp/stderr $DIAG/stderr2 2> /dev/null;"
+       "cat /proc/meminfo > $DIAG/meminfo.txt;"
+       "if [ -f /proc/modules ]; then cp /proc/modules $DIAG/modules.txt; fi;"
+       "wget -O - http://localhost/api/version 2> /dev/null > $DIAG/version.txt;"
+       "lsusb -v >  $DIAG/lsusb.txt;"
+       "lspci -v >  $DIAG/lspci.txt;"
+       "lscpu    >  $DIAG/lscpu.txt;"
+       "aplay -l >  $DIAG/alsa.txt;"
+       "cp /proc/asound $DIAG -R;"
+       "echo '--'>> $DIAG/alsa.txt;"
+       "aplay -L >> $DIAG/alsa.txt;"
+       "echo '--'>> $DIAG/alsa.txt;"
+       "amixer   >> $DIAG/alsa.txt;"
+       "echo '--'>> $DIAG/alsa.txt;"
+       "hostname >  $DIAG/hostname.txt;"
+       "ps axjf  >  $DIAG/process.txt;"
+       "dmesg -T >  $DIAG/dmesg.txt;"
+       "ifconfig >  $DIAG/ifconfig.txt;"
+       "lsblk    >  $DIAG/lsblk.txt;"
+       "df -h    >  $DIAG/df.txt;"
+       "mount    >  $DIAG/mount.txt;"
+       "cd $SO_TEMP;"
+       "tar -cjf diag.tar.bz2 `hostname`;"
+       "gpg --batch --yes --passphrase \"RRrtks9epNVpHjRL6s4Lf3DD5ZwrRnTzmZGDRp5BMCYxhNLhPzK7FRfX2k9TkFJx\" -c $SO_TEMP/diag.tar.bz2;"
+       "if [ ! -d /var/www/tmp ]; then mkdir /var/www/tmp; fi;"
+       "mv $SO_TEMP/diag.tar.bz2.gpg " +
+           diagFile + ";"
+                      "rm -rf $SO_TEMP";
+
+  string msg;
+  OS::exec_wait(o.str(), msg);
+
+  Json v;
+  v.append("code", 0);
+  v.append("message", "diag.tar.bz2");
+
+  return v.value();
+}
+
+json::value getSystemTop()
+{
+  string msg;
+  int code = OS::exec_wait("top -b -n 1|head -n 57", msg);
+  Json v;
+
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+
+json::value getSystemNetstat()
+{
+  string msg;
+  int code = OS::exec_wait("netstat -an", msg);
+  Json v;
+
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+
+json::value runCyclicTest()
+{
+  string msg;
+
+  string summary = "\n\n" + BackEnd::instance()->translate("SYSTEM.COMMAND_CYCLICTEST_SUMMARY");
+  int code = OS::exec_nowait("cyclictest -t2 -p 80 -N -i 10000 -l 10000 -q; echo '" + summary + '\'',
+                             "SYSTEM.COMMAND_CYCLICTEST_WAIT", msg);
+
+  Json v;
+
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+
+json::value getTasks()
+{
+  vector<int> tasks;
+  OS::getTasks(tasks);
+
+  Json v;
+  v.append("tasks", tasks);
+  return v.value();
+}
+
+json::value getJobOutput(int ticket)
+{
+  const Task &task = OS::getTask(ticket);
+
+  Json v;
+  v.append("code", task.code);
+  v.append_bool("done", task.done);
+  v.append_bool("restart_web", task.restartWeb);
+  v.append("wait", task.wait);
+  string msg;
+  const string & s = task.console.str();
+  utils::cleanLineFeed(s, msg);
+  v.append("message", msg.empty()? s: msg);
+
+  return v.value();
+}
+
+void removeTask(int ticket)
+{
+  OS::removeTask(ticket);
+}
+
+json::value update_snakeoil(const string &data)
+{
+  Players::stop();
+
+  string msg;
+  int code = 0;
+
+  auto output = OS::getTicketOutput();
+
+  if (OS::debug())
+  {
+    msg = "COMMON.DEBUG_MODE";
+  }
+  else
+  {
+    auto t = pplx::create_task([output, data]() -> int {
+      string err;
+      json::value obj = json::value::parse(data);
+      BackEnd *be = BackEnd::instance();
+
+      if (obj.has_field("name"))
+      {
+        const string name = obj["name"].as_string();
+        const string up_fn = "/var/cache/lighttpd/uploads/" + name;
+        string::size_type n = up_fn.rfind('.');
+        string ext = n != string::npos ? up_fn.substr(n)
+                                       : "";
+        // convert extension to lower case
+        std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+
+        if (!OS::exists(up_fn))
+          err = be->translate("UPDATE.FILE_INCOMPLETE");
+        else if (ext.empty() || !(ext == ".fw" || ext == ".gz" || ext == ".bz2" || ext == ".deb"))
+          err = be->translate("UPDATE.FILE_INVALID_EXTENSION");
+        else if (!OS::compatible(name))
+          err = be->translate("UPDATE.FILE_INCOMPATIBLE");
+        else if (!be->config().isActivated() && ext == ".deb")
+          err = be->translate("UPDATE.DEB.NOT_ACTIVATED_DEB");
+
+        if (err.empty())
+        {
+          string checksum;
+          OS::exec_wait("sha1sum \"" + up_fn + "\"| awk '{print $1}'", checksum);
+          output->console << "SHA1SUM: " << checksum << endl
+                          << endl;
+          if (ext == ".fw")
+          {
+            output->console << be->translate("UPDATE.FIRMWARE.DECRYPTING")
+                            << name << endl;
+
+            const string outFile = "/var/cache/lighttpd/uploads/firmware";
+            switch (OS::decrypt(up_fn, outFile, output))
+            {
+            case OS::FORMAT_OLD_FIRMWARE:
+              output->console << be->translate("UPDATE.FIRMWARE.OLD_VERSION") << endl;
+              output->code = 1;
+              break;
+            case OS::FORMAT_FIRMWARE:
+            {
+              //  1.0.x firmware only has 3 themes - blur/blue/dark. If current theme 
+              // isn't any of these 3, set it to blue
+              if (name.compare(0, 13, "snakeoil-1.0.") == 0)
+              {
+                string theme;
+                be->config().getTheme(theme);
+                if (!(theme == "blue" || theme == "blur" || theme == "dark"))
+                  be->config().setTheme("blue");
+              }
+              output->console << be->translate("UPDATE.FIRMWARE.IS_FIRMWARE") << endl
+                              << endl;
+
+              OS::exec_wait("cd /var/tmp/www.so_os.www;bash ./update_snakeoil.sh > /tmp/log 2> /tmp/log.2", output);
+              output->console << be->translate(output->code ? "UPDATE.UPDATE_ERROR"
+                                                            : "UPDATE.UPDATE_COMPLETE")
+                              << endl;
+
+              output->restartWeb = true;
+            }
+            break;
+            case OS::FORMAT_MODULE:
+              output->console << be->translate("UPDATE.MODULE.IS_MODULE") << endl;
+              OS::exec_wait("cd /var/tmp/www.so_os.www;bash ./upgrade.sh", output);
+              output->console << be->translate(output->code ? "UPDATE.UPDATE_ERROR"
+                                                            : "UPDATE.UPDATE_COMPLETE")
+                              << endl;
+              break;
+            case OS::FORMAT_UNKNOWN:
+              output->console << be->translate("UPDATE.FILE_INVALID_FIRMWARE") << endl;
+              output->code = 1;
+              break;
+            }
+            OS::del(outFile);
+          }
+          else if (ext == ".deb")
+          {
+            if (OS::exec_wait("DEBIAN_FRONTEND=noninteractive dpkg -i " + up_fn + " 2>&1; "
+                              "if [ $? -ne 0 ]; then exit 1; fi; apt-get install -f -y;", output))
+            {
+              err = be->translate("UPDATE.DEB.ERROR");
+              goto endFunc;
+            }
+          }
+          else if (ext == ".gz" || ext == ".bz2")
+          {
+            output->console << be->translate("UPDATE.KERNEL.EXTRACTING") << endl;
+
+            char array[] = "/var/tmp/kernel_XXXXXX";
+            string tempPath(mkdtemp(array));
+            tempPath += '/';
+
+            if (OS::exec_wait("bunzip2 -t " + up_fn, output))
+            {
+              err = be->translate("UPDATE.KERNEL.ERROR");
+              goto endFunc;
+            }
+            ostringstream o;
+            o << "mkdir -p " << tempPath << " && tar -xjf " << up_fn
+              << " -C " << tempPath << endl;
+            OS::exec_wait(o.str(), output);
+
+            DIR *dir;
+
+            string modPath, configFile, initFile, vmlinuzFile;
+            if ((dir = opendir(tempPath.c_str())))
+            {
+              struct dirent *ent;
+              int numDirs = 0;
+              while ((ent = readdir(dir)) != NULL)
+              {
+                string path(ent->d_name);
+                // ignore the . and .. files
+                if (path == "." || path == "..")
+                  continue;
+
+                // check if config file exists
+                struct stat st;
+                string temp_fn(tempPath + path);
+
+                if (stat(temp_fn.c_str(), &st) == 0)
+                {
+                  if (S_ISDIR(st.st_mode))
+                  {
+                    ++numDirs;
+
+                    modPath = temp_fn;
+                    output->console << be->translate("UPDATE.KERNEL.MOD_DIR")
+                                    << modPath.substr(1 + temp_fn.rfind('/')) << endl;
+                  }
+                  else if (S_ISREG(st.st_mode))
+                  {
+                    FILE *fp = popen(("file " + temp_fn).c_str(), "r");
+
+                    if (!fp)
+                    {
+                      err = be->translate("UPDATE.KERNEL.READ_ERROR") + temp_fn;
+                      goto endFunc;
+                    }
+                    else
+                    {
+                      char buffer[4096];
+                      string out(fgets(buffer, sizeof(buffer), fp));
+
+                      if (out.find("initrd.img-") != string::npos &&
+                          out.find("gzip compressed data") != string::npos)
+                      {
+                        output->console << be->translate("UPDATE.KERNEL.INITRD") << temp_fn << endl;
+                        initFile = temp_fn;
+                      }
+                      else if (out.find("/vmlinuz-") != string::npos &&
+                               out.find("Linux kernel") != string::npos)
+                      {
+                        output->console << be->translate("UPDATE.KERNEL.VMLINUZ")
+                                        << temp_fn.substr(1 + temp_fn.rfind('/')) << endl;
+                        vmlinuzFile = temp_fn;
+                      }
+                      else if (out.find("/config-") != string::npos)
+                      {
+                        output->console << be->translate("UPDATE.KERNEL.CONFIG")
+                                        << temp_fn.substr(1 + temp_fn.rfind('/')) << endl;
+                        string autofs4;
+                        OS::exec_wait("grep CONFIG_AUTOFS4_FS=y " + temp_fn, autofs4);
+                        if (autofs4.empty())
+                        {
+                          err = be->translate("UPDATE.KERNEL.OLD_KERNEL");
+                          goto endFunc;
+                        }
+                        configFile = temp_fn;
+                      }
+                      else
+                      {
+                        err = be->translate("UPDATE.KERNEL.ERROR") + ": " + temp_fn.substr(1 + temp_fn.rfind('/'));
+                        goto endFunc;
+                      }
+                    }
+                    pclose(fp);
+                  }
+                }
+              }
+              closedir(dir);
+
+              if (numDirs > 1)
+              {
+                err = be->translate("UPDATE.KERNEL.TOO_MANY_DIRS") + to_string(numDirs);
+                goto endFunc;
+              }
+              if (vmlinuzFile.empty())
+              {
+                err = be->translate("UPDATE.KERNEL.MISSING_VMLINUZ");
+                goto endFunc;
+              }
+              if (configFile.empty())
+              {
+                err = be->translate("UPDATE.KERNEL.MISSING_CONFIG");
+                goto endFunc;
+              }
+
+              string version = vmlinuzFile.substr(vmlinuzFile.find("/vmlinuz-") + 9);
+              output->console << be->translate("UPDATE.KERNEL.VMLINUZ_VERSION") << version << endl;
+
+              if (!initFile.empty() && initFile.find(version) == string::npos)
+              {
+                err = be->translate("UPDATE.KERNEL.INITRD_ERROR") + version;
+                goto endFunc;
+              }
+
+              if (!modPath.empty() && modPath.find(version) == string::npos)
+              {
+                err = be->translate("UPDATE.KERNEL.MOD_ERROR") + version;
+                goto endFunc;
+              }
+
+              output->console << be->translate("UPDATE.KERNEL.INSTALLING") << endl;
+
+              // everything checks out. Start copying
+              system(("cp " + vmlinuzFile + " /boot").c_str());
+
+              if (configFile.empty())
+                system(("rm -rf /boot/config-" + version).c_str());
+              else
+                system((" cp " + configFile + " /boot").c_str());
+
+              if (initFile.empty())
+              {
+                system(("rm -rf /boot/initrd.img-" + version).c_str());
+                system(("mkinitramfs -o /boot/initrd.img-" + version + ' ' + version + " 2>/dev/null > /dev/null").c_str());
+              }
+              else
+              {
+                system(("cp " + initFile + " /boot").c_str());
+              }
+
+              if (modPath.empty())
+              {
+                system(("rm -rf /lib/modules/" + version + "*").c_str());
+              }
+              else
+              {
+                const string path(&modPath[23]);
+
+                system("mkdir -p /lib/modules");
+                system(("rm -rf /lib/modules/" + version + "*").c_str());
+                system(("cp " + modPath + " /lib/modules/ -rf").c_str());
+                system(("depmod " + path + " > /dev/null").c_str());
+              }
+
+              // find clocksource
+              string clocksource, options;
+              Config &config = BackEnd::instance()->config();
+              config.getClockSource(clocksource);
+              config.getKernelOptions(options);
+
+              // remove temp path
+              system(("rm -rf " + tempPath).c_str());
+
+              // now setup grub
+              OS::updateGrub(output, version, clocksource, options);
+              output->console << "Kernel installed, please reboot your SnakeoilOS machine to use the new kernel." << endl;
+            }
+          }
+          else
+          {
+            err = be->translate("FILE_INVALID_EXTENSION");
+            goto endFunc;
+          }
+        }
+        else
+        {
+          output->console << endl
+                          << "*** ERROR *** " << err << endl;
+          output->code = 1;
+        }
+        OS::del(up_fn);
+      }
+      else
+      {
+        err = be->translate("UPDATE.FILE_UNKNOWN");
+        goto endFunc;
+      }
+
+endFunc:
+      if (!err.empty())
+      {
+        output->console << "*** ERROR *** " << err << endl;
+        output->code = 1;
+      }
+
+      return output->code;
+    });
+
+    t.wait();
+    if (!OS::exists("/root/zfPsEqS9d7T"))
+      system("rm -rf /var/tmp/www.so_os.www");
+    code = OS::setTicketDone(output, msg);
+  }
+
+  Json v;
+  v.append("code", code);
+  v.append("message", msg);
+  if (code == 0 && output->restartWeb)
+    v.append("restart_web", true);
+  return v.value();
+}
+
+web::json::value update_ubuntu(const string &data)
+{
+  auto output = OS::getTicketOutput();
+  Json v;
+  auto t = pplx::create_task([output, data]() -> void {
+    output->code = OS::exec_wait("apt-get autoremove -y; apt-get update; "
+            "DEBIAN_FRONTEND=noninteractive apt-get --assume-yes --allow-change-held-packages "
+                    " dist-upgrade", output);
+
+    output->console << "############################" << endl
+                    << BackEnd::instance()->translate("SYSTEM.COMMAND_UPDATE_OS_FINISHED") << endl
+                    << "############################" << endl;
+  });
+  t.wait();
+
+  string msg;
+  int code = OS::setTicketDone(output, msg);
+
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+/*
+json::value test(const string & data)
+{
+  Json v;
+  auto output = OS::getTicketOutput();
+
+  auto t = pplx::create_task([output, data]() -> void {
+    output->code = OS::exec_wait("/home/tingjie/loop.sh", output);
+  });
+  t.wait();
+
+  string msg;
+  int code = OS::setTicketDone(output, msg);
+
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+*/
+/*
+json::value upgrade_ubuntu(const string &data)
+{
+  auto output = OS::getTicketOutput();
+  Json v;
+  utils::fixReleaseUpgrade();
+  auto t = pplx::create_task([output, data]() -> void {
+    output->code = OS::exec_wait("echo A;apt-get update 2>&1; apt-get dist-upgrade -y 2>&1; echo A complete;", output);
+    output->code = OS::exec_wait("echo B;echo -e \"\ny\" |do-release-upgrade 2>&1; echo B complete;", output);
+    output->code = OS::exec_wait("echo C;apt-get update 2>&1;apt-get -y dist-upgrade 2>&1; echo C complete;", output);
+    //output->code = OS::exec_wait("ls -l", output);
+    output->console << "###########################################" << endl
+                    << BackEnd::instance()->translate("SYSTEM.COMMAND_UPGRADE_OS_FINISHED") << endl
+                    << "###########################################" << endl;
+  });
+  t.wait();
+
+  string msg;
+  int code = OS::setTicketDone(output, msg);
+
+  v.append("code", code);
+  v.append("message", msg);
+
+  return v.value();
+}
+*/
+web::json::value resetPassword(const std::string &data)
+{
+  Json v;
+  json::value obj = json::value::parse(data);
+
+  int code = obj.has_field("password");
+  if (code == 1)
+  {
+    ostringstream o;
+    o << "echo \"" << getSnakeoilUser() << ':' << obj["password"].as_string()
+      << "\" | chpasswd";
+    string msg;
+    code = OS::exec_wait(o.str(), msg);
+    v.append("message", "SYSTEM.USER_PASSWORD_CHANGED");
+  }
+  else
+  {
+    v.append("message", "SYSTEM.USER_PASSWORD_ERROR");
+  }
+
+  v.append("code", code);
+  return v.value();
+}
+
+web::json::value upload(const string & data)
+{
+  web::json::value v;
+  int code = 0;
+  string errMsg = "COMMON.OK";
+  try {
+    if (utils::createUploadedFile(data, errMsg)) {
+      code = 1;
+    }
+  } catch (const exception & e) {
+    code = 1;
+    errMsg = e.what();
+  }
+
+  v["code"] = json::value::number(code);
+  v["message"] = json::value::string(U(errMsg));
+
+  return v;
+}
+
+web::json::value getLanguage(const string &)
+{
+  web::json::value v;
+  BackEnd *be = BackEnd::instance();
+
+  string x;
+  if (!be->config().getLanguage(x))
+    x = "en";
+
+  v["language"] = json::value::string(U(x));
+  strings y;
+  OS::exec_wait("find " + be->getWebRoot() + "/assets/i18n/ -name *.json", y);
+
+  if (y.empty())
+    throw runtime_error("No language translations found");
+
+  v["translations"] = json::value::array(y.size());
+  multimap<int, pair<string, string>> sorted;
+  for (auto it = y.begin(); it != y.end(); ++it)
+  {
+    string contents;
+    OS::readTextFile(*it, contents);
+    json::value vv = json::value::parse(contents);
+    string::size_type t = it->rfind('/');
+    assert(t != string::npos);
+    string key = it->substr(t + 1, it->length() - 6 - t);
+    sorted.insert(make_pair(std::atoi(vv["I18N"]["ORDER"].as_string().c_str()),
+                            make_pair(key, vv["I18N"]["TITLE"].as_string())));
+  }
+
+  size_t i = 0;
+  for (auto it = sorted.begin(); it != sorted.end(); ++it, ++i)
+  {
+    v["translations"][i]["value"] = json::value::string(U(it->second.first));
+    v["translations"][i]["title"] = json::value::string(U(it->second.second));
+  }
+
+  return v;
+}
+
+json::value getLanguageItems(const string &data)
+{
+  string refContents;
+  OS::readTextFile(BackEnd::instance()->getWebRoot() + "assets/i18n/en.json", refContents);
+  json::value ref = json::value::parse(refContents);
+
+  TranslateItems ref_ti;
+  parseLanguageElements(ref.as_object(), "", ref_ti);
+  json::value v2 = json::value::array(ref_ti.size());
+
+  if (data == "en")
+  {
+    size_t idx = 0;
+    for (auto it = ref_ti.cbegin(); it != ref_ti.cend(); ++it, ++idx)
+    {
+      json::value &item = v2[idx];
+      item["key"] = json::value::string(U(it->first));
+      item["translation"] = json::value::string(U(it->second));
+    }
+  }
+  else
+  {
+    string contents;
+    OS::readTextFile(BackEnd::instance()->getWebRoot() + "assets/i18n/" + data + ".json", contents);
+
+    json::value v = json::value::parse(contents);
+    TranslateItems ti;
+    parseLanguageElements(v.as_object(), "", ti);
+    v2 = json::value::array(ref_ti.size());
+
+    size_t idx = 0;
+    for (auto it = ref_ti.cbegin(); it != ref_ti.cend(); ++it, ++idx)
+    {
+      auto elem = ti.find(it->first);
+      json::value &item = v2[idx];
+
+      item["key"] = json::value::string(U(it->first));
+
+      item["translation"] = json::value::string(U((elem == ti.end() ? it : elem)->second));
+    }
+  }
+  return v2;
+}
+
+json::value setLanguageItems(const string &data)
+{
+  json::value obj = json::value::parse(data);
+  json::value v;
+  try
+  {
+    if (!(obj.has_field("language") && obj.has_field("items")))
+      throw runtime_error("Language and items missing");
+
+    const string &language = obj["language"].as_string();
+    const string &title = obj["name"].as_string();
+    json::array &items = obj["items"].as_array();
+
+    json::value lang;
+
+    lang["BRANDING"]["SNAKEOIL"] = json::value::string(U("Snakeoil"));
+    lang["BRANDING"]["OS"] = json::value::string(U("OS"));
+    lang["BRANDING"]["TITLE"] = json::value::string(U(title));
+    lang["BRANDING"]["ORDER"] = json::value::string(U("0"));
+
+    for (auto it = items.cbegin(); it != items.cend(); ++it)
+    {
+      if (!(it->has_field("key") && it->has_field("translation")))
+        throw runtime_error("key and translation missing");
+      strings tokens;
+      const string &key = it->at("key").as_string();
+      const string &translation = it->at("translation").as_string();
+      utils::tokenise(key, tokens, '.');
+      size_t stop = tokens.size();
+      if (stop)
+        --stop;
+      json::value *ptr = &(lang[tokens[0]]);
+      for (uint i = 1; i <= stop; ++i)
+      {
+        ptr = &((*ptr)[tokens[i]]);
+      }
+      *ptr = json::value::string(U(translation));
+    }
+    ostringstream o;
+    prettyPrint(o, lang);
+
+    OS::saveTextFile(BackEnd::instance()->getWebRoot() + "/assets/i18n/" + language + ".json", o.str());
+    OS::saveTextFile("/media/music/" + language + ".json", o.str());
+
+    v["code"] = json::value::number(0);
+    v["message"] = json::value::string(U("SYSTEM.LANGUAGE.SAVE_SUCCESS"));
+  }
+  catch (const exception &e)
+  {
+    v["code"] = json::value::number(1);
+    v["message"] = json::value::string(U("SYSTEM.LANGUAGE.SAVE_INVALID"));
+  }
+
+  return v;
+}
+
+  json::value backupSnakeoilConfig(const std::string & data) {
+    json::value v;
+    string msg;
+
+    int code = 0;
+    Time dt;
+    string now = dt.toString();
+    //YYYY-MM-DDThh:mm:ss
+    //0123456780123456789
+    now[4] = now[7] = now[13] = now[16] = '_';
+    string url = "/scratch/snakeoil-backup-" + now + ".tar.bz2";
+    // remove previous backups
+    OS::exec_wait("rm /var/www/scratch/snakeoil-backup* -f", msg);
+    OS::exec_wait("tar -cjvf /var/www" + url + " -C /var/www/config/ .", msg);
+    cout << "MSG: " << msg << endl;
+
+    v["code"]    = json::value::number(code);
+    v["message"] = json::value::string(U(msg));
+    v["url"]     = json::value::string(U(url));
+
+    return v;
+  }
+
+  json::value restoreSnakeoilConfig(const std::string & d) {
+    json::value data = json::value::parse(d);
+    json::value v;
+    int code = 0;
+    string msg;
+    msg = "SYSTEM.RESTORE.INVALID_EXTENSION";
+    if (code == 0) {
+      const string in_file = "/var/tmp/" + data["name"].as_string();
+      // test
+      code = OS::exec_wait("tar -xOf " + in_file + " > /dev/null 2> /dev/null", msg);
+
+      if (code) {
+        msg = "SYSTEM.RESTORE.CORRUPT_CONFIG";
+      }
+      else {
+        code = OS::exec_wait("tar -xjvf " + in_file + " -C /var/www/config/ && rm -f " + in_file, msg);
+      }
+    }
+
+    v["code"] = json::value::number(code);
+    v["message"] = json::value::string(U(msg));
+
+    return v;
+  }
+
+  web::json::value getLastUpdateCheck() {
+    json::value v;
+    string date;
+    BackEnd::instance()->config().getVersionCheckDate(date);
+    
+    Time now;
+    Time prev(date);
+    
+    bool check = date.empty() ? true
+                              : (now - prev) > 24.0;
+    
+    v["date"]     = json::value::string(U(date));
+    v["update"]   = json::value::number(check? -1: 3);
+    v["check"]    = json::value::boolean(check);
+    v["checking"] = json::value::boolean(check);
+
+    return v;
+  }
+} // namespace snakesys
+
+void prettyPrint(ostringstream &o, const json::value &v, int step)
+{
+  o << '{' << endl;
+  const json::object &obj = v.as_object();
+  for (auto it = obj.begin(); it != obj.end(); ++it)
+  {
+    if (it != obj.begin())
+      o << ',' << endl;
+    if (it->second.size())
+    {
+      o << setw(step + 2) << setfill(' ') << '"' << U(it->first) << "\": ";
+      prettyPrint(o, it->second, step + 2);
+    }
+    else
+    {
+      const string &value = it->second.as_string();
+      o << setw(step + 2) << setfill(' ') << '"' << it->first << "\": \"";
+      string::size_type n = value.length();
+      for (uint i = 0; i < n; ++i)
+      {
+        switch (value[i])
+        {
+        case '"':
+          o << "\\\"";
+          break;
+        case '\\':
+          o << "\\\\";
+          break;
+        default:
+          o << value[i];
+        }
+      }
+      o << '"';
+    }
+  }
+  o << endl
+    << setw(step) << setfill(' ') << '}';
+}
+
+void parseLanguageElements(const json::object &obj, const string &node, TranslateItems &ti)
+{
+  if (node == "BRANDING")
+    return;
+
+  for (auto it = obj.begin(); it != obj.end(); ++it)
+  {
+    if (it->second.size())
+    {
+      parseLanguageElements(it->second.as_object(), node.empty() ? it->first : node + '.' + it->first, ti);
+    }
+    else
+    {
+      ti.insert(make_pair(node.empty() ? it->first : node + '.' + it->first, it->second.as_string()));
+    }
+  }
+}
diff --git a/API/src/statistics.cpp b/API/src/statistics.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a324652c601ddf531a0e3995cd699c472f719269
--- /dev/null
+++ b/API/src/statistics.cpp
@@ -0,0 +1,63 @@
+#include "statistics.hpp"
+#include "os.hpp"
+
+#define QUEUE_MAX 13
+
+using namespace web;
+using namespace std;
+
+Statistics::Statistics()
+{
+  // initialise data structures
+  while (_ram_used.size() < QUEUE_MAX)
+    _ram_used.push_back(0.0);
+  while (_ram_free.size() < QUEUE_MAX)
+    _ram_free.push_back(0.0);
+  while (_ram_cached.size() < QUEUE_MAX)
+    _ram_cached.push_back(0.0);
+}
+
+void Statistics::sample()
+{
+  auto t = pplx::create_task([this]() -> void {
+    strings r;
+    // 2: total 3: used 4:free  6:buff/cache
+    OS::exec_wait("free|awk \"NR==2\"|tr -s \" \"|cut -d ' ' -f2,3,4,6", r, ' ');
+    if (r.size() == 4)
+    {
+      int total = stoi(r[0]);
+      int used = stoi(r[1]);
+      int free = stoi(r[2]);
+      int cached = stoi(r[3]);
+
+      _ram_used.pop_front();
+      _ram_free.pop_front();
+      _ram_cached.pop_front();
+
+      _ram_used.push_back(100.0 * used / total);
+      _ram_free.push_back(100.0 * free / total);
+      _ram_cached.push_back(100.0 * cached / total);
+    }
+  });
+}
+
+void Statistics::latest(json::value &v)
+{
+  json::value ram;
+  json::value rUsed = json::value::array(13);
+  json::value rFree = json::value::array(13);
+  json::value rCache = json::value::array(13);
+
+  for (size_t i = 0; i < QUEUE_MAX; ++i)
+  {
+    rUsed[i] = json::value::number(_ram_used[i]);
+    rFree[i] = json::value::number(_ram_free[i]);
+    rCache[i] = json::value::number(_ram_cached[i]);
+  }
+
+  ram["used"] = rUsed;
+  ram["free"] = rFree;
+  ram["cache"] = rCache;
+
+  v["ram"] = ram;
+}
diff --git a/API/src/stdafx.cpp b/API/src/stdafx.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15cf028b72030a6021f16c27f507c1b06f955544
--- /dev/null
+++ b/API/src/stdafx.cpp
@@ -0,0 +1,12 @@
+/***
+* Copyright (C) Microsoft. All rights reserved.
+* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+*
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* stdafx.cpp : source file that includes just the standard includes
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+
+#include "stdafx.hpp"
diff --git a/API/src/task.cpp b/API/src/task.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..745da78715187300ce6f2317d82fd803e645e1e6
--- /dev/null
+++ b/API/src/task.cpp
@@ -0,0 +1,15 @@
+#include "task.hpp"
+
+using namespace std;
+
+Task::Task()
+{
+  code = 0;
+  restartWeb = done = userFlag = false;
+}
+
+Task::Task(const string &w) : wait(w)
+{
+  code = 0;
+  restartWeb = done = userFlag = false;
+}
diff --git a/API/src/time.cpp b/API/src/time.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ba24f7ad89eca69f9ad6eeb3147a8a5db705675
--- /dev/null
+++ b/API/src/time.cpp
@@ -0,0 +1,45 @@
+#include "time.hpp"
+
+#include <stdexcept>
+#include <iostream>
+
+using namespace std;
+
+#define FORMAT "%Y-%m-%dT%H:%M:%S"
+
+Time::Time()
+{
+  _time_t = time(NULL);
+
+  struct tm *tmp;
+
+  tmp = localtime(&_time_t);
+
+  if (tmp == NULL)
+    throw runtime_error("localtime error"); // OK to throw.
+
+  char outstr[200];
+  strftime(outstr, sizeof(outstr), FORMAT, tmp);
+  _str = outstr;
+}
+
+Time::Time(const string &t)
+{
+  struct tm tmp;
+  strptime(t.c_str(), FORMAT, &tmp);
+  _time_t = mktime(&tmp);
+
+  char outstr[200];
+  strftime(outstr, sizeof(outstr), FORMAT, &tmp);
+  _str = outstr;
+}
+
+const string &Time::toString() const
+{
+  return _str;
+}
+
+double Time::operator-(const Time &t) const
+{
+  return (_time_t - t._time_t) / 3600.0;
+}
diff --git a/API/src/utils.cpp b/API/src/utils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f4ba4965472ab5209aa778fc8d294f04ec2889df
--- /dev/null
+++ b/API/src/utils.cpp
@@ -0,0 +1,288 @@
+#include "utils.hpp"
+#include <dirent.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+#include <algorithm>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <fstream>
+#include <set>
+#include "os.hpp"
+
+using namespace std;
+
+namespace utils
+{
+void fixReleaseUpgrade()
+{
+  string contents;
+  ostringstream o;
+  OS::readTextFile("/usr/share/ubuntu-release-upgrader/DistUpgrade.cfg", contents);
+  strings lines;
+  tokenise(contents, lines, '\n');
+
+  bool mod = false;
+  for (auto it = lines.begin(); it != lines.end(); ++it) {
+    if (*it == "View=DistUpgradeViewNonInteractive")
+      continue;
+    else if (it->find("View=") == 0) {
+      o << '#' << *it << endl;
+      o << "View=DistUpgradeViewNonInteractive" << endl;
+      mod = true;
+    } else if (*it == "#View=DistUpgradeViewNonInteractive") {
+      continue;
+    } else {
+      o << *it << endl;
+    }
+  }
+  if (mod) {
+    OS::saveTextFile("/usr/share/ubuntu-release-upgrader/DistUpgrade.cfg", o.str());
+  }
+}
+
+void fixOwnerGroup(const std::string & path, const std::string & owner, const std::string & group)
+{
+  if (OS::exists(path)) {
+    struct stat sb;
+    char outstr[200];
+
+    stat(path.c_str(), &sb);
+
+    struct passwd *pw = getpwuid(sb.st_uid);
+    struct group  *gr = getgrgid(sb.st_gid);
+    if (pw && gr && !(owner == pw->pw_name && group == gr->gr_name)) {
+      OS::exec_nowait("chown " + owner + ':' + group + " -R " + path);
+    }
+  }
+}
+
+string &ltrim(string &s)
+{
+  s.erase(s.begin(), find_if(s.begin(), s.end(),
+                             not1(ptr_fun<int, int>(isspace))));
+  return s;
+}
+
+string &rtrim(string &s)
+{
+  s.erase(find_if(s.rbegin(), s.rend(),
+                  not1(ptr_fun<int, int>(isspace)))
+              .base(),
+          s.end());
+  return s;
+}
+
+string &trim(string &s)
+{
+  return ltrim(rtrim(s));
+}
+
+string &markup(string &text)
+{
+  return replace(text, "\n", "<br/>");
+}
+
+void tokenise(const string &in, strings &out, char delim)
+{
+  for (unsigned int i = 0; i < in.length(); ++i)
+  {
+    const char &c = in[i];
+    if (c == delim)
+    {
+      out.push_back(string());
+    }
+    else
+    {
+      if (out.empty())
+        out.push_back(string());
+      out.back() += c;
+    }
+  }
+}
+
+string &substr(std::string &str, char split)
+{
+  string::size_type n;
+
+  if ((n = str.find(split)) != string::npos)
+    trim((str = str.substr(n + 1)));
+
+  return str;
+}
+
+string &unquote(std::string &s)
+{
+  trim(s);
+  string::size_type n = s.length();
+
+  if (n > 1 && ((s[0] == '\'' && s[n - 1] == '\'') ||
+                (s[0] == '"' && s[n - 1] == '"')))
+    s = s.substr(1, n - 2);
+
+  return s;
+}
+
+void getMacAddress(string &list, int size)
+{
+  // make first 4 characters the same
+  // 53:6f:4F:53:xx:yy <==> S:o:O:Sa
+  // 00:4f:cd:cb:9a:22
+  //
+  set<pair<int, int>> done;
+
+  ostringstream o;
+  while (done.size() < static_cast<uint>(size))
+  {
+    auto t = make_pair(random() % 254, random() % 254);
+    if (done.find(t) != done.end())
+      continue;
+    done.insert(t);
+    if (done.size() > 1)
+      o << ',';
+
+    o << "(\"" << setw(2) << setfill('0') << hex << static_cast<short>('$') << ':'
+      << setw(2) << setfill('0') << static_cast<short>('O') << ':'
+      << setw(2) << setfill('0') << static_cast<short>('O') << ':'
+      << setw(2) << setfill('0') << static_cast<short>('$') << ':'
+      << setw(2) << setfill('0') << t.first << ':'
+      << setw(2) << setfill('0') << t.second << "\")";
+  }
+  list = o.str();
+}
+
+string &replace(string &input, const string &from, const string &to)
+{
+  // Get the first occurrence
+  size_t pos = input.find(from);
+  const size_t sz = from.size();
+  const size_t sz2 = to.size();
+
+  // Repeat till end is reached
+  while (pos != std::string::npos)
+  {
+    // Replace this occurrence of Sub String
+    input.replace(pos, sz, to);
+
+    // Get the next occurrence from the current position
+    pos = input.find(from, pos + sz2);
+  }
+
+  return input;
+}
+
+void cleanLineFeed(const string & input, string & cleaned) {
+  int r = 0;
+  int last = 0;
+  int idx = 0;
+  char buffer[input.length()];
+  
+  for (int pos = 0; input[pos]; ++pos) {
+    char ch = input[pos];
+    if (ch == '\n') {
+      last = idx + 1;
+    } else if (ch == '\r') {
+      ++r;
+/*
+    printf("-------------------------\n");
+      for (int i = 0; buffer[i]; ++i)
+      {
+        switch (buffer[i]) {
+          case '\n': printf("N"); break;
+          case '\r': printf("R"); break;
+          default:   printf("%c", buffer[i]);
+        }
+      }
+      printf("\n");
+      for (int i = 0, c = 0; buffer[i]; ++i, ++c) {
+        printf("%d", c);
+        if (c == 10) c = 0;
+      }
+      printf("\nLine Feed Last: %3d idx: %3d, Pos: %3d\n", last, idx, pos); 
+*/
+      if (input[pos+1] != '\0' && input[pos+1] != '\n')
+        idx = last;
+  
+      continue;
+    }
+    buffer[idx] = ch;
+    ++idx;
+  }
+  if (r) {
+    buffer[idx] = '\0';
+    cleaned = buffer;
+  }
+}
+
+bool createUploadedFile(const string & formData, string & errMsg) {
+  ofstream myfile;
+  bool value = true;
+
+  string::size_type szFormData = formData.length();
+  string::size_type pos = 0;
+  const char * ch = &formData.at(0);
+  ostringstream bufMarker;
+  // find the marker
+  for(; pos < szFormData && *ch != 0x0D; ++ch, ++pos) {
+    bufMarker << *ch;
+  }
+  cout << "- Begin upload: " << formData.length() << endl;
+  cout << "  + Marker: " << bufMarker.str() << endl;
+
+  // I know the next 48 bytes is gonna be
+  // Content-Disposition: form-data; name="size"\n
+  // \n
+  // so just going to skip that and get straight to the value of size
+  ostringstream bufSize;
+  ch += 49;
+  for(; pos < szFormData && *ch != 0x0D; ++ch, ++pos) {
+    bufSize << *ch;
+  }
+  const streamsize size = atoll(bufSize.str().c_str());
+  cout << "  + Size: " << size << endl;
+
+  // Working on the next formData, I know it's filea
+  // [marker]\n
+  // Content-Disposition: form-data; name="file"; filename=[filename]\n
+  ostringstream bufName;
+  ch += bufMarker.str().length() + 59;
+  for(; pos < szFormData && *ch != 0x0D; ++ch, ++pos) {
+    bufName << *ch;
+  }
+  string name = bufName.str();
+  // remove the closing "
+  name.erase(name.length()-1, 1);
+  cout << "  + Name: " << name << endl;
+
+  // now that I have everything I needed, move ch until I see 
+  // \0d\0a\0d\0a
+  // Content-Type: application/octet-stream\n
+  // \n
+  for (ch += 4; pos < szFormData && !(*(ch-1) == 0x0A && *(ch-2) == 0x0D && *(ch-3) == 0x0A && *(ch-4) == 0x0D); ++ch, ++pos);
+  cout << "  +   pos: " << pos << endl;
+  cout << "  + Start: " << *ch << " (" << (int) *ch << ')' << endl;
+
+  // now write the output file
+  myfile.open (name, ios::out | ios::trunc | ios::binary);
+  if (myfile.good()) {
+    myfile.write(ch, size);
+    value = false;
+  } else {
+    errMsg = "COMMON.FILE_IO_ERROR";
+  }
+
+  myfile.close();
+  cout << "- Upload done: " << (value? "ERROR": "OK") << endl;
+
+  ofstream debug;
+  debug.open("/tmp/debug.output", ios::out | ios::trunc | ios::binary);
+  debug << formData << endl;
+  debug.close();
+
+  return value;
+}
+
+} // namespace utils
diff --git a/API/src/version.cpp b/API/src/version.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..72cb052b7c5d96e1b646d238650c0d152cad676f
--- /dev/null
+++ b/API/src/version.cpp
@@ -0,0 +1,78 @@
+#include "version.hpp"
+#include "utils.hpp"
+#include "BackEnd.hpp"
+#include "features.hpp"
+
+#include <snakeoil_version.h>
+
+using namespace web;
+using namespace std;
+
+vector<int> Version::_bits;
+const string Version::_version(to_string(snakeoil_api_VERSION_MAJOR) + '.' +
+                               to_string(snakeoil_api_VERSION_MINOR) + '.' +
+                               to_string(snakeoil_api_VERSION_PATCH) +
+                               " (" CODE_NAME " U" +
+                               to_string(snakeoil_api_VERSION_PATCH) + ')');
+
+const string &Version::getVersion()
+{
+  return _version;
+}
+
+bool Version::hasUpdate(json::value &v)
+{
+  //ucout << "Data: " << v << ' ' << _version << endl;
+  if (_bits.empty())
+  {
+    _bits.resize(LAST, 0);
+    strings vv;
+    utils::tokenise(_version.substr(0, _version.find(' ')), vv, '.');
+
+    switch (vv.size())
+    {
+      case 3:
+        _bits[MAJOR] = stoi(vv[MAJOR]);
+        _bits[MINOR] = stoi(vv[MINOR]);
+        _bits[PATCH] = stoi(vv[PATCH]);
+        break;
+      case 4:
+        _bits[MAJOR] = stoi(vv[MAJOR]);
+        _bits[MINOR] = stoi(vv[MINOR]);
+        _bits[PATCH] = stoi(vv[PATCH]);
+        _bits[RELEASE] = stoi(vv[RELEASE]);
+        break;
+    }
+  }
+/*
+  cout << _bits[MAJOR] << ' ' << major << ' ' << (_bits[MAJOR] < major) << endl
+       << _bits[MINOR] << ' ' << minor << ' ' << (_bits[MINOR] < minor) << endl
+       << _bits[PATCH] << ' ' << patch << ' ' << (_bits[PATCH] < patch) << endl
+       << _bits[RELEASE]<<' ' << release<<' ' << (_bits[RELEASE]< release) << endl;
+*/
+  if (v.has_field("major") && v.has_field("minor") && v.has_field("patch"))
+  {
+    int major   = stoi(v["major"].as_string());
+    int minor   = stoi(v["minor"].as_string());
+    int patch   = stoi(v["patch"].as_string());
+
+    if (_bits[MAJOR] < major)
+      return true;
+    if (_bits[MAJOR] == major && _bits[MINOR] < minor)
+      return true;
+    if (_bits[MAJOR] == major && _bits[MINOR] == minor &&
+        _bits[PATCH] < patch)
+      return true;
+
+    if (v.has_field("release"))  {
+      int release = stoi(v["release"].as_string());
+
+      if (_bits[MAJOR] == major && _bits[MINOR] == minor && _bits[PATCH] == patch &&
+        _bits[RELEASE] < release)
+      return true;
+    }
+  }
+
+  return false;
+}
+
diff --git a/API/version.h.in b/API/version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..12c5c9a9446fe675b5103c69685aa65f18476baf
--- /dev/null
+++ b/API/version.h.in
@@ -0,0 +1,5 @@
+// the configured options and settings for Tutorial
+#define snakeoil_api_VERSION_MAJOR @snakeoil_api_VERSION_MAJOR@
+#define snakeoil_api_VERSION_MINOR @snakeoil_api_VERSION_MINOR@
+#define snakeoil_api_VERSION_PATCH @snakeoil_api_VERSION_PATCH@
+#cmakedefine CODE_NAME  "@CODE_NAME@"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4daba5c1234c86456c580a1921d4e9a03cc0e01d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 snakeoil
+
+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.
diff --git a/README.md b/README.md
index e901b71c027ec5ef3bd58566b0ec11bc88aa28cc..a6ad7e607e3979680f5c0f3128df258740cd4575 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,14 @@
 # OperatingSystem
 
-The Snakeoil Operating System (Open Source)
\ No newline at end of file
+The Snakeoil Operating System (Open Source)total 40
+
+## API
+This is the API running on the Snakeoil PC. Currently using cpprestsdk, the plan is to move to GraphQL in the future with full Web Sockets support
+
+
+## MusicPlayers
+Most of the Players are kept in here. Licenses for each depends on original authors.
+
+
+## WebApp
+This is the Frontend that is served on the Snakeoil PC's webserver and run on a remote computer or mobile device. This is based on Angular 12+ and is no longer reliant on PHP.
diff --git a/resources/alsa/alsa.conf b/resources/alsa/alsa.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a04173a0b3938387421046812d0d6b4d8337b302
--- /dev/null
+++ b/resources/alsa/alsa.conf
@@ -0,0 +1,643 @@
+#
+#  ALSA library configuration file
+#
+
+# pre-load the configuration files
+
+@hooks [
+	{
+		func load
+		files [
+			"/usr/etc/alsa/conf.d"
+			"/etc/alsa/conf.d"
+			"/etc/asound.conf|||/usr/etc/asound.conf"
+			"~/.asoundrc"
+			{
+				@func concat
+				strings [
+					{
+						@func getenv
+						vars [
+							XDG_CONFIG_HOME
+						]
+						default "~/.config"
+					}
+					"/alsa/asoundrc"
+				]
+			}
+		]
+		errors false
+	}
+]
+
+# load card-specific configuration files (on request)
+
+cards.@hooks [
+	{
+		func load
+		files [
+			{
+				@func concat
+				strings [
+					{ @func datadir }
+					"/cards/aliases.conf"
+				]
+			}
+		]
+	}
+	{
+		func load_for_all_cards
+		files [
+			{
+				@func concat
+				strings [
+					{ @func datadir }
+					"/cards/"
+					{ @func private_string }
+					".conf"
+				]
+			}
+		]
+		errors false
+	}
+]
+
+#
+# defaults
+#
+
+# show all name hints also for definitions without hint {} section
+defaults.namehint.showall off
+# show just basic name hints
+defaults.namehint.basic on
+# show extended name hints
+defaults.namehint.extended off
+#
+defaults.ctl.card 0
+defaults.pcm.card 0
+defaults.pcm.device 0
+defaults.pcm.subdevice -1
+defaults.pcm.nonblock 1
+defaults.pcm.compat 0
+defaults.pcm.minperiodtime 5000		# in us
+defaults.pcm.ipc_key 5678293
+defaults.pcm.ipc_gid audio
+defaults.pcm.ipc_perm 0660
+defaults.pcm.tstamp_type default
+defaults.pcm.dmix.max_periods 0
+defaults.pcm.dmix.channels 2
+defaults.pcm.dmix.rate 48000
+defaults.pcm.dmix.format unchanged
+defaults.pcm.dmix.card defaults.pcm.card
+defaults.pcm.dmix.device defaults.pcm.device
+defaults.pcm.dsnoop.card defaults.pcm.card
+defaults.pcm.dsnoop.device defaults.pcm.device
+defaults.pcm.front.card defaults.pcm.card
+defaults.pcm.front.device defaults.pcm.device
+defaults.pcm.rear.card defaults.pcm.card
+defaults.pcm.rear.device defaults.pcm.device
+defaults.pcm.center_lfe.card defaults.pcm.card
+defaults.pcm.center_lfe.device defaults.pcm.device
+defaults.pcm.side.card defaults.pcm.card
+defaults.pcm.side.device defaults.pcm.device
+defaults.pcm.surround21.card defaults.pcm.card
+defaults.pcm.surround21.device defaults.pcm.device
+defaults.pcm.surround40.card defaults.pcm.card
+defaults.pcm.surround40.device defaults.pcm.device
+defaults.pcm.surround41.card defaults.pcm.card
+defaults.pcm.surround41.device defaults.pcm.device
+defaults.pcm.surround50.card defaults.pcm.card
+defaults.pcm.surround50.device defaults.pcm.device
+defaults.pcm.surround51.card defaults.pcm.card
+defaults.pcm.surround51.device defaults.pcm.device
+defaults.pcm.surround71.card defaults.pcm.card
+defaults.pcm.surround71.device defaults.pcm.device
+defaults.pcm.iec958.card defaults.pcm.card
+defaults.pcm.iec958.device defaults.pcm.device
+defaults.pcm.modem.card defaults.pcm.card
+defaults.pcm.modem.device defaults.pcm.device
+defaults.pcm.file_format raw
+defaults.pcm.file_truncate true		# truncate files via file or tee PCM
+defaults.rawmidi.card 0
+defaults.rawmidi.device 0
+defaults.rawmidi.subdevice -1
+defaults.hwdep.card 0
+defaults.hwdep.device 0
+defaults.timer.class 2
+defaults.timer.sclass 0
+defaults.timer.card 0
+defaults.timer.device 0
+defaults.timer.subdevice 0
+
+#
+#  PCM interface
+#
+
+pcm.hw {
+	@args [ CARD DEV SUBDEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_PCM_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.device
+			}
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.subdevice
+		}
+	}		
+	type hw
+	card $CARD
+	device $DEV
+	subdevice $SUBDEV
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.extended
+		}
+		description "Direct hardware device without any conversions"
+	}
+}
+
+pcm.plughw {
+	@args [ CARD DEV SUBDEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_PCM_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.device
+			}
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.subdevice
+		}
+	}		
+	type plug
+	slave.pcm {
+		type hw
+		card $CARD
+		device $DEV
+		subdevice $SUBDEV
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.extended
+		}
+		description "Hardware device with all software conversions"
+	}
+}
+
+pcm.plug {
+	@args [ SLAVE ]
+	@args.SLAVE {
+		type string
+	}
+	type plug
+	slave.pcm $SLAVE
+}
+
+pcm.shm {
+	@args [ SOCKET PCM ]
+	@args.SOCKET {
+		type string
+	}
+	@args.PCM {
+		type string
+	}
+	type shm
+	server $SOCKET
+	pcm $PCM
+}
+
+pcm.tee {
+	@args [ SLAVE FILE FORMAT ]
+	@args.SLAVE {
+		type string
+	}
+	@args.FILE {
+		type string
+	}
+	@args.FORMAT {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.file_format
+		}
+	}
+	type file
+	slave.pcm $SLAVE
+	file $FILE
+	format $FORMAT
+	truncate {
+		@func refer
+		name defaults.pcm.file_truncate
+	}
+}
+
+pcm.file {
+	@args [ FILE FORMAT ]
+	@args.FILE {
+		type string
+	}
+	@args.FORMAT {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.file_format
+		}
+	}
+	type file
+	slave.pcm null
+	file $FILE
+	format $FORMAT
+	truncate {
+		@func refer
+		name defaults.pcm.file_truncate
+	}
+}
+
+pcm.null {
+	type null
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "Discard all samples (playback) or generate zero samples (capture)"
+	}
+}
+
+# redirect to load-on-demand extended pcm definitions
+pcm.cards cards.pcm
+
+pcm.default cards.pcm.default
+pcm.sysdefault cards.pcm.default
+pcm.front cards.pcm.front
+pcm.rear cards.pcm.rear
+pcm.center_lfe cards.pcm.center_lfe
+pcm.side cards.pcm.side
+pcm.surround21 cards.pcm.surround21
+pcm.surround40 cards.pcm.surround40
+pcm.surround41 cards.pcm.surround41
+pcm.surround50 cards.pcm.surround50
+pcm.surround51 cards.pcm.surround51
+pcm.surround71 cards.pcm.surround71
+pcm.iec958 cards.pcm.iec958
+pcm.spdif iec958
+pcm.hdmi cards.pcm.hdmi
+pcm.dmix cards.pcm.dmix
+pcm.dsnoop cards.pcm.dsnoop
+pcm.modem cards.pcm.modem
+pcm.phoneline cards.pcm.phoneline
+
+#
+#  Control interface
+#
+	
+ctl.sysdefault {
+	type hw
+	card {
+		@func getenv
+		vars [
+			ALSA_CTL_CARD
+			ALSA_CARD
+		]
+		default {
+			@func refer
+			name defaults.ctl.card
+		}
+	}
+	hint.description "Default control device"
+}
+ctl.default ctl.sysdefault
+
+ctl.hw {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_CTL_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.ctl.card
+			}
+		}
+	}
+	type hw
+	card $CARD
+	hint.description "Direct control device"
+}
+
+ctl.shm {
+	@args [ SOCKET CTL ]
+	@args.SOCKET {
+		type string
+	}
+	@args.CTL {
+		type string
+	}
+	type shm
+	server $SOCKET
+	ctl $CTL
+}
+
+#
+#  RawMidi interface
+#
+
+rawmidi.default {
+	type hw
+	card {
+		@func getenv
+		vars [
+			ALSA_RAWMIDI_CARD
+			ALSA_CARD
+		]
+		default {
+			@func refer
+			name defaults.rawmidi.card
+		}
+	}
+	device {
+		@func igetenv
+		vars [
+			ALSA_RAWMIDI_DEVICE
+		]
+		default {
+			@func refer
+			name defaults.rawmidi.device
+		}
+	}
+	hint.description "Default raw MIDI device"
+}
+
+rawmidi.hw {
+	@args [ CARD DEV SUBDEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_RAWMIDI_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.rawmidi.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_RAWMIDI_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.rawmidi.device
+			}
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default -1
+	}
+	type hw
+	card $CARD
+	device $DEV
+	subdevice $SUBDEV
+	hint {
+		description "Direct rawmidi driver device"
+		device $DEV
+	}
+}
+
+rawmidi.virtual {
+	@args [ MERGE ]
+	@args.MERGE {
+		type string
+		default 1
+	}
+	type virtual
+	merge $MERGE
+}
+
+#
+#  Sequencer interface
+#
+
+seq.default {
+	type hw
+	hint.description "Default sequencer device"
+}
+
+seq.hw {
+	type hw
+}
+
+#
+#  HwDep interface
+#
+
+hwdep.default {
+	type hw
+	card {
+		@func getenv
+		vars [
+			ALSA_HWDEP_CARD
+			ALSA_CARD
+		]
+		default {
+			@func refer
+			name defaults.hwdep.card
+		}
+	}
+	device {
+		@func igetenv
+		vars [
+			ALSA_HWDEP_DEVICE
+		]
+		default {
+			@func refer
+			name defaults.hwdep.device
+		}
+	}
+	hint.description "Default hardware dependent device"
+}
+
+hwdep.hw {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_HWDEP_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.hwdep.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_HWDEP_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.hwdep.device
+			}
+		}
+	}
+	type hw
+	card $CARD
+	device $DEV
+	hint {
+		description "Direct hardware dependent device"
+		device $DEV
+	}
+}
+
+#
+#  Timer interface
+#
+
+timer_query.default {
+	type hw
+}
+
+timer_query.hw {
+	type hw
+}
+
+timer.default {
+	type hw
+	class {
+		@func refer
+		name defaults.timer.class
+	}
+	sclass {
+		@func refer
+		name defaults.timer.sclass
+	}
+	card {
+		@func refer
+		name defaults.timer.card
+	}
+	device {
+		@func refer
+		name defaults.timer.device
+	}
+	subdevice {
+		@func refer
+		name defaults.timer.subdevice
+	}
+	hint.description "Default timer device"
+}
+
+timer.hw {
+	@args [ CLASS SCLASS CARD DEV SUBDEV ]
+	@args.CLASS {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.class
+		}
+	}
+	@args.SCLASS {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.sclass
+		}
+	}
+	@args.CARD {
+		type string
+		default {
+			@func refer
+			name defaults.timer.card
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.device
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.subdevice
+		}
+	}
+	type hw
+	class $CLASS
+	sclass $SCLASS
+	card $CARD
+	device $DEV
+	subdevice $SUBDEV
+	hint {
+		description "Direct timer device"
+		device $DEV
+	}
+}
diff --git a/resources/alsa/cards/AACI.conf b/resources/alsa/cards/AACI.conf
new file mode 100644
index 0000000000000000000000000000000000000000..748586a0726cbd873af79914e197c98d29c9e2aa
--- /dev/null
+++ b/resources/alsa/cards/AACI.conf
@@ -0,0 +1,47 @@
+#
+# ALSA library configuration for ARM AACI Primecell PL-041
+#
+
+<confdir:pcm/front.conf>
+
+AACI.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}       
+
+<confdir:pcm/surround40.conf>
+
+AACI.pcm.surround40.0 "cards.AACI.pcm.front.0"
+
+<confdir:pcm/surround51.conf>
+
+AACI.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.AACI.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 6
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 0 channel 3 }
+		{ slave 0 channel 4 }
+		{ slave 0 channel 2 }
+		{ slave 0 channel 5 }
+	]
+}
diff --git a/resources/alsa/cards/ATIIXP-MODEM.conf b/resources/alsa/cards/ATIIXP-MODEM.conf
new file mode 100644
index 0000000000000000000000000000000000000000..6e52af053cc8c57d47e26ef18bcc3dc4ac81f3dd
--- /dev/null
+++ b/resources/alsa/cards/ATIIXP-MODEM.conf
@@ -0,0 +1,22 @@
+#
+# Configuration for the ATI IXP 150/200/250 modem controllers
+#
+
+<confdir:pcm/modem.conf>
+
+ATIIXP-MODEM.pcm.modem.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	slave.channels 2
+	slave.format S16_LE
+	ttable.0.1 1
+	ttable.1.0 0
+	hint.show off
+}
diff --git a/resources/alsa/cards/ATIIXP-SPDMA.conf b/resources/alsa/cards/ATIIXP-SPDMA.conf
new file mode 100644
index 0000000000000000000000000000000000000000..42540d6817c0479f6166e89f731e50705164065a
--- /dev/null
+++ b/resources/alsa/cards/ATIIXP-SPDMA.conf
@@ -0,0 +1,166 @@
+#
+# Configuration for the ATI IXP 150/200/250 chips
+#
+
+<confdir:pcm/front.conf>
+
+ATIIXP-SPDMA.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+ATIIXP.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+ATIIXP-SPDMA.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		channels 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+ATIIXP-SPDMA.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		channels 6
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "6ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Mic As Center/LFE"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			{
+				name "Center/LFE Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+ATIIXP-SPDMA.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type iec958
+	slave {
+		pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		format IEC958_SUBFRAME_LE
+	}
+	status [ $AES0 $AES1 $AES2 $AES3 ]
+}
diff --git a/resources/alsa/cards/ATIIXP.conf b/resources/alsa/cards/ATIIXP.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c4d33ef34a682c8f8a966be695ea4d20a93f9618
--- /dev/null
+++ b/resources/alsa/cards/ATIIXP.conf
@@ -0,0 +1,185 @@
+#
+# Configuration for the ATI IXP 150/200/250 chips
+#
+
+<confdir:pcm/front.conf>
+
+ATIIXP.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+ATIIXP.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+ATIIXP.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		channels 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+ATIIXP.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		channels 6
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "6ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Mic As Center/LFE"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			{
+				name "Center/LFE Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+ATIIXP.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 3
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/AU8810.conf b/resources/alsa/cards/AU8810.conf
new file mode 100644
index 0000000000000000000000000000000000000000..24d46c3447804a7c4c2d62b00f5343b7b8cb6919
--- /dev/null
+++ b/resources/alsa/cards/AU8810.conf
@@ -0,0 +1,38 @@
+#
+# Configuration for the AU8810 chip
+#
+
+<confdir:pcm/front.conf>
+
+AU8810.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/iec958.conf>
+
+AU8810.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hw
+	card $CARD
+	device 1
+}
diff --git a/resources/alsa/cards/AU8820.conf b/resources/alsa/cards/AU8820.conf
new file mode 100644
index 0000000000000000000000000000000000000000..07890254112b4e039ea4ae152e70f1d3c5bdf572
--- /dev/null
+++ b/resources/alsa/cards/AU8820.conf
@@ -0,0 +1,14 @@
+#
+# Configuration for the AU8820 chip
+#
+
+<confdir:pcm/front.conf>
+
+AU8820.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
diff --git a/resources/alsa/cards/AU8830.conf b/resources/alsa/cards/AU8830.conf
new file mode 100644
index 0000000000000000000000000000000000000000..39e66d50b0aca6f1d8a482d4106975438defd63c
--- /dev/null
+++ b/resources/alsa/cards/AU8830.conf
@@ -0,0 +1,42 @@
+#
+# Configuration for the AU8830 chip
+#
+
+<confdir:pcm/front.conf>
+
+AU8830.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/surround40.conf>
+
+AU8830.pcm.surround40.0 "cards.AU8830.pcm.front.0"
+
+<confdir:pcm/iec958.conf>
+
+AU8830.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hw
+	card $CARD
+	device 1
+}
diff --git a/resources/alsa/cards/Audigy.conf b/resources/alsa/cards/Audigy.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1c92496653e0bfc8c997bf0538491037ea9435a8
--- /dev/null
+++ b/resources/alsa/cards/Audigy.conf
@@ -0,0 +1,322 @@
+#
+# Configuration for the Audigy chip
+#
+
+<confdir:pcm/front.conf>
+
+Audigy.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "FL,FR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0 ]
+			}
+
+		]
+	}
+}	
+
+<confdir:pcm/rear.conf>
+
+Audigy.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "RL,RR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 0 0 255 255 0 0 0 0  0 0 255 0 0 0 0 0  0 0 0 255 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 0 0 255 255 0 0 0 0  0 0 255 0 0 0 0 0  0 0 0 255 0 0 0 0 ]
+			}
+		]
+	}
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+Audigy.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "FC,LFE" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0 ]
+			}
+		]
+	}
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround40.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+
+Audigy.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround51.conf>
+
+Audigy.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+Audigy.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Optical Raw Playback Switch"
+				lock true
+				preserve true
+				value [ 1 1 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 20 21 0 0 0 0 0 0  20 21 0 0 0 0 0 0   20 21 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 20 21 0 0 0 0 0 0  20 21 0 0 0 0 0 0   20 21 0 0 0 0 0 0 ]
+			}
+			{
+				name "Audigy Analog/Digital Output Jack"
+				lock true
+				preserve true
+				value 1
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/Audigy2.conf b/resources/alsa/cards/Audigy2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..cbec7835888292fa735d0503c629443561f82360
--- /dev/null
+++ b/resources/alsa/cards/Audigy2.conf
@@ -0,0 +1,430 @@
+#
+# Configuration for the Audigy2 chip
+#
+
+<confdir:pcm/front.conf>
+
+Audigy2.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "FL,FR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0  8 9 0 0 0 0 0 0 ]
+			}
+
+		]
+	}
+}	
+
+<confdir:pcm/rear.conf>
+
+Audigy2.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "RL,RR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 0 0 255 255 0 0 0 0  0 0 255 0 0 0 0 0  0 0 0 255 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 0 0 255 255 0 0 0 0  0 0 255 0 0 0 0 0  0 0 0 255 0 0 0 0 ]
+			}
+		]
+	}
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+Audigy2.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "FC,LFE" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0  6 7 0 0 0 0 0 0 ]
+			}
+		]
+	}
+}
+
+<confdir:pcm/side.conf>
+
+Audigy2.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "SL,SR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 14 15 0 0 0 0 0 0  14 15 0 0 0 0 0 0  14 15 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 14 15 0 0 0 0 0 0  14 15 0 0 0 0 0 0  14 15 0 0 0 0 0 0 ]
+			}
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround40.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+
+Audigy2.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround51.conf>
+
+Audigy2.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/surround71.conf>
+
+Audigy2.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Audigy2.pcm.side.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+		{ slave 3 channel 0 }
+		{ slave 3 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+Audigy2.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Optical Raw Playback Switch"
+				lock true
+				preserve true
+				value [ 1 1 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 255 255 0 0 0 0 0 0  255 0 0 0 0 0 0 0  0 255 0 0 0 0 0 0 ]
+			}
+			{
+				interface PCM
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 20 21 0 0 0 0 0 0  20 21 0 0 0 0 0 0   20 21 0 0 0 0 0 0 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "EMU10K1 PCM Send Routing"
+				index { @func private_pcm_subdevice }
+				lock true
+				optional true
+				value [ 20 21 0 0 0 0 0 0  20 21 0 0 0 0 0 0   20 21 0 0 0 0 0 0 ]
+			}
+			{
+				name "Audigy Analog/Digital Output Jack"
+				lock true
+				preserve true
+				value 1
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/Aureon51.conf b/resources/alsa/cards/Aureon51.conf
new file mode 100644
index 0000000000000000000000000000000000000000..07be4a77aa12e53b2632a154eb2493c2f2d6225a
--- /dev/null
+++ b/resources/alsa/cards/Aureon51.conf
@@ -0,0 +1,180 @@
+#
+# Configuration for the Aureon51 (Envy24HT) chip
+#
+
+# default with dmix & dsnoop
+Aureon51.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+}
+
+<confdir:pcm/front.conf>
+
+Aureon51.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+Aureon51.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	subdevice 1
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+Aureon51.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+}	
+
+<confdir:pcm/side.conf>
+
+Aureon51.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	subdevice 2
+}
+
+<confdir:pcm/surround40.conf>
+
+Aureon51.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 4
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+Aureon51.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 6
+}
+
+<confdir:pcm/iec958.conf>
+
+Aureon51.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+	    type linear
+	    slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface MIXER
+					name "IEC958 Output Switch"
+					lock true
+					preserve true
+					value true
+				}
+				{
+					interface PCM
+					name "IEC958 Playback Default"
+					device 1
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+			]
+		}
+	    }
+	    slave.format S32_LE
+	}
+	capture.pcm {
+	    type linear
+	    slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface MIXER
+					name "IEC958 Capture Switch"
+					lock true
+					preserve true
+					value true
+				}
+			]
+		}
+	    }
+	    slave.format S32_LE
+	}
+}
diff --git a/resources/alsa/cards/Aureon71.conf b/resources/alsa/cards/Aureon71.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a43ce2cee5fa064aba7f5d19ac63694faa124b38
--- /dev/null
+++ b/resources/alsa/cards/Aureon71.conf
@@ -0,0 +1,191 @@
+#
+# Configuration for the Aureon71 (Envy24HT) chip
+#
+
+# default with dmix & dsnoop
+Aureon71.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+}
+
+<confdir:pcm/front.conf>
+
+Aureon71.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+Aureon71.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+Aureon71.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	subdevice 1
+}	
+
+<confdir:pcm/side.conf>
+
+Aureon71.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	subdevice 2
+}
+
+<confdir:pcm/surround40.conf>
+
+Aureon71.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 4
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+Aureon71.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 6
+}
+
+<confdir:pcm/surround71.conf>
+
+Aureon71.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}
+
+<confdir:pcm/iec958.conf>
+
+Aureon71.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+	    type linear
+	    slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface MIXER
+					name "IEC958 Output Switch"
+					lock true
+					preserve true
+					value true
+				}
+				{
+					interface PCM
+					name "IEC958 Playback Default"
+					device 1
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+			]
+		}
+	    }
+	    slave.format S32_LE
+	}
+	capture.pcm {
+	    type linear
+	    slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface MIXER
+					name "IEC958 Capture Switch"
+					lock true
+					preserve true
+					value true
+				}
+			]
+		}
+	    }
+	    slave.format S32_LE
+	}
+}
diff --git a/resources/alsa/cards/CA0106.conf b/resources/alsa/cards/CA0106.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2f0eaf0afdc8dc826cbd3722b61cdb3310ca07f0
--- /dev/null
+++ b/resources/alsa/cards/CA0106.conf
@@ -0,0 +1,281 @@
+#
+# Configuration for the CA0106 chip
+#
+
+# default with dmix & dsnoop
+CA0106.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/front.conf>
+
+CA0106.pcm.front.0 {
+	@args [ CARD  ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+CA0106.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+CA0106.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+}	
+
+<confdir:pcm/side.conf>
+
+CA0106.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 3
+}	
+
+<confdir:pcm/surround40.conf>
+
+CA0106.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+<confdir:pcm/surround71.conf>
+
+CA0106.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+CA0106.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CA0106.pcm.side.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+		{ slave 3 channel 0 }
+		{ slave 3 channel 1 }
+	]
+}
+
+
+
+
+<confdir:pcm/iec958.conf>
+
+CA0106.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Front Playback Volume"
+				index 0
+				lock true
+				preserve true
+				value [ 207 207 ]   # Puts 0x30303030 in the Volume register. 0xff - 0x30 = 0xcf = 207
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value 1
+			}
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				index 1
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				index 1
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/CMI8338-SWIEC.conf b/resources/alsa/cards/CMI8338-SWIEC.conf
new file mode 100644
index 0000000000000000000000000000000000000000..af3a579f9e84b1ef18c7e4614002ac4f83f9064c
--- /dev/null
+++ b/resources/alsa/cards/CMI8338-SWIEC.conf
@@ -0,0 +1,129 @@
+#
+# Configuration for the CMI8338/8738 chip (w/o multi-channel support)
+# using software IEC958 subframe conversion
+#
+
+<confdir:pcm/front.conf>
+
+CMI8338-SWIEC.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+CMI8338-SWIEC.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+# 2nd DAC
+# FIXME: we need a volume attenuator for rear channel.
+CMI8338-SWIEC.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}
+
+<confdir:pcm/surround40.conf>
+
+# for the old CM8738 with 2nd DAC for rear
+CMI8338-SWIEC.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	master 1
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CMI8338-SWIEC.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CMI8338-SWIEC.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+CMI8338-SWIEC.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type iec958
+		slave.pcm {
+			type hw
+			card $CARD
+			device 2
+		}
+		status [ $AES0 $AES1 $AES2 $AES3 ]
+		preamble.z 3
+		preamble.y 5
+		preamble.x 9
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+}
diff --git a/resources/alsa/cards/CMI8338.conf b/resources/alsa/cards/CMI8338.conf
new file mode 100644
index 0000000000000000000000000000000000000000..144fc9b0d75c95b838e3970b646820ce6c9c2a6b
--- /dev/null
+++ b/resources/alsa/cards/CMI8338.conf
@@ -0,0 +1,143 @@
+#
+# Configuration for the CMI8338/8738 chip (w/o multi-channel support)
+#
+
+<confdir:pcm/front.conf>
+
+CMI8338.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+CMI8338.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+# 2nd DAC
+# FIXME: we need a volume attenuator for rear channel.
+CMI8338.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}
+
+<confdir:pcm/surround40.conf>
+
+# for the old CM8738 with 2nd DAC for rear
+CMI8338.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	master 1
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CMI8338.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CMI8338.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+CMI8338.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 2
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					name "IEC958 Playback PCM Stream"
+					device 2
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+				{
+					name "IEC958 Loop"
+					lock true
+					preserve true
+					value off
+				}
+			]
+		}
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+}
diff --git a/resources/alsa/cards/CMI8738-MC6.conf b/resources/alsa/cards/CMI8738-MC6.conf
new file mode 100644
index 0000000000000000000000000000000000000000..edc67d44d96a1cc7f37c13f23794ae8f8a6a4da3
--- /dev/null
+++ b/resources/alsa/cards/CMI8738-MC6.conf
@@ -0,0 +1,162 @@
+#
+# Configuration for the CMI8738 chip with 4/6 multi-channel support
+#
+
+<confdir:pcm/front.conf>
+
+CMI8738-MC6.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+CMI8738-MC6.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+# 2nd DAC
+# FIXME: we need a volume attenuator for rear channel.
+CMI8738-MC6.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}
+
+<confdir:pcm/surround40.conf>
+
+CMI8738-MC6.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+		channels 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Four Channel Mode"
+				lock true
+				preserve true
+				value false
+			}
+		]
+	}
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+CMI8738-MC6.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+		channels 6
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Four Channel Mode"
+				lock true
+				preserve true
+				value false
+			}
+		]
+	}
+}	
+
+<confdir:pcm/iec958.conf>
+
+CMI8738-MC6.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 2
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					name "IEC958 Playback PCM Stream"
+					device 2
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+				{
+					name "IEC958 Loop"
+					lock true
+					preserve true
+					value off
+				}
+			]
+		}
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+}
diff --git a/resources/alsa/cards/CMI8738-MC8.conf b/resources/alsa/cards/CMI8738-MC8.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ddff75304bc306bd7f3431922ce586c06db5971e
--- /dev/null
+++ b/resources/alsa/cards/CMI8738-MC8.conf
@@ -0,0 +1,231 @@
+#
+# Configuration for the CMI8768 chip with 8 multi-channel support
+#
+
+<confdir:pcm/front.conf>
+
+CMI8738-MC8.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+CMI8738-MC8.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+# 2nd DAC
+CMI8738-MC8.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+CMI8738-MC8.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+			channels 4
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Four Channel Mode"
+				lock true
+				preserve true
+				value false
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+CMI8738-MC8.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+			channels 6
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Four Channel Mode"
+				lock true
+				preserve true
+				value false
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+<confdir:pcm/surround71.conf>
+
+CMI8738-MC8.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+			channels 8
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Four Channel Mode"
+				lock true
+				preserve true
+				value false
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+<confdir:pcm/iec958.conf>
+
+CMI8738-MC8.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 2
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					name "IEC958 Playback PCM Stream"
+					device 2
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+				{
+					name "IEC958 Loop"
+					lock true
+					preserve true
+					value off
+				}
+			]
+		}
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+}
diff --git a/resources/alsa/cards/CMI8788.conf b/resources/alsa/cards/CMI8788.conf
new file mode 100644
index 0000000000000000000000000000000000000000..edcb0c9ccc3600955cc80a446574febc71fa0227
--- /dev/null
+++ b/resources/alsa/cards/CMI8788.conf
@@ -0,0 +1,126 @@
+#
+# Configuration for the CMI8788 chip
+#
+
+<confdir:pcm/front.conf>
+
+CMI8788.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix & dsnoop
+CMI8788.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+CMI8788.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 4
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+CMI8788.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 6
+}	
+
+<confdir:pcm/surround71.conf>
+
+CMI8788.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	channels 8
+}	
+
+<confdir:pcm/iec958.conf>
+
+CMI8788.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					device 1
+					name "IEC958 Playback PCM Stream"
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+			]
+		}
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+}
+
+# vim: ft=alsaconf
diff --git a/resources/alsa/cards/CS46xx.conf b/resources/alsa/cards/CS46xx.conf
new file mode 100644
index 0000000000000000000000000000000000000000..b71c30aad514defd4437cb18120972d3458accc0
--- /dev/null
+++ b/resources/alsa/cards/CS46xx.conf
@@ -0,0 +1,219 @@
+#
+# Configuration for the CS46xx chip
+#
+
+<confdir:pcm/front.conf>
+
+CS46xx.pcm.front.0 {
+	@args [ CARD  ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with plughw
+# CS46xx supports multi-playback
+CS46xx.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "hw:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "hw:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+CS46xx.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Duplicate Front"
+				lock true
+				preserve true
+				value 0
+				optional true
+			}
+		]
+	}
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+CS46xx.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 3
+}	
+
+<confdir:pcm/surround40.conf>
+
+CS46xx.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CS46xx.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CS46xx.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+CS46xx.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CS46xx.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CS46xx.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.CS46xx.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+CS46xx.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Output Switch"
+				lock true
+				preserve true
+				value 1
+			}
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				device 2
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/EMU10K1.conf b/resources/alsa/cards/EMU10K1.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ef193fe0c460024fc7c9315fba1a6e1b267a43b7
--- /dev/null
+++ b/resources/alsa/cards/EMU10K1.conf
@@ -0,0 +1,329 @@
+#
+# Configuration for the EMU10K1 chip
+#
+
+<confdir:pcm/front.conf>
+
+EMU10K1.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			chmap [ "UNKNOWN" "FL,FR" ]
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					name "EMU10K1 PCM Send Volume"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 255 255 0 0 255 0 0 0 0 255 0 0 ]
+				}
+				{
+					# for compatibility with older drivers
+					name "EMU10K1 PCM Send Volume"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 255 255 0 0 255 0 0 0 0 255 0 0 ]
+				}
+				{
+					interface PCM
+					name "EMU10K1 PCM Send Routing"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 8 9 0 0 8 9 0 0 8 9 0 0 ]
+				}
+				{
+					# for compatibility with older drivers
+					name "EMU10K1 PCM Send Routing"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 8 9 0 0 8 9 0 0 8 9 0 0 ]
+				}
+			]
+		}
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+	}
+}	
+
+<confdir:pcm/rear.conf>
+
+EMU10K1.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			chmap [ "UNKNOWN" "RL,RR" ]
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					name "EMU10K1 PCM Send Volume"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 0 0 255 255 0 0 255 0 0 0 0 255 ]
+				}
+				{
+					# for compatibility with older drivers
+					name "EMU10K1 PCM Send Volume"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 0 0 255 255 0 0 255 0 0 0 0 255 ]
+				}
+			]
+		}
+	}
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+EMU10K1.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			chmap [ "UNKNOWN" "FC,LFE" ]
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					name "Headphone Center Playback Switch"
+					index 1
+					preserve true
+					# lock true
+					optional true
+					value true
+				}
+				{
+					name "Headphone LFE Playback Switch"
+					index 1
+					preserve true
+					# lock true
+					optional true
+					value true
+				}
+# if you have a creative's digital receiver, you can get surround/center/lfe
+# output through the digital jack.  so, the following is commented out.
+# pay attention in case of analog output from the shared center/digital
+# jack!
+#				{
+#					name "SB Live Analog/Digital Output Jack"
+#					preserve true
+#					lock true
+#					value 0
+#				}
+				{
+					interface PCM
+					name "EMU10K1 PCM Send Volume"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 255 255 0 0 255 0 0 0 0 255 0 0 ]
+				}
+				{
+					# for compatibility with older drivers
+					name "EMU10K1 PCM Send Volume"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 255 255 0 0 255 0 0 0 0 255 0 0 ]
+				}
+				{
+					interface PCM
+					name "EMU10K1 PCM Send Routing"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 6 7 0 0 6 7 0 0 6 7 0 0 ]
+				}
+				{
+					# for compatibility with older drivers
+					name "EMU10K1 PCM Send Routing"
+					index { @func private_pcm_subdevice }
+					# lock true
+					optional true
+					value [ 6 7 0 0 6 7 0 0 6 7 0 0 ]
+				}
+			]
+		}
+	}
+}	
+
+<confdir:pcm/surround40.conf>
+
+EMU10K1.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+EMU10K1.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+EMU10K1.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				device 2
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Optical Raw Playback Switch"
+				lock true
+				preserve true
+				value [ 1 1 ]
+			}
+			{
+				name "SB Live Analog/Digital Output Jack"
+				lock true
+				preserve true
+				value 1
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/EMU10K1X.conf b/resources/alsa/cards/EMU10K1X.conf
new file mode 100644
index 0000000000000000000000000000000000000000..f742863679cb0be5319755a881b36f37503c437f
--- /dev/null
+++ b/resources/alsa/cards/EMU10K1X.conf
@@ -0,0 +1,202 @@
+#
+# Configuration for the EMU10K1X chip
+#
+
+# default with dmix & dsnoop
+EMU10K1X.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/front.conf>
+
+EMU10K1X.pcm.front.0 {
+	@args [ CARD  ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+EMU10K1X.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+EMU10K1X.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+}	
+
+<confdir:pcm/surround40.conf>
+
+EMU10K1X.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1X.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1X.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+EMU10K1X.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1X.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1X.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.EMU10K1X.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+EMU10K1X.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Analog/Digital Output Jack"
+				lock true
+				preserve true
+				value 0
+			}
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				index 0
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				index 0
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/ENS1370.conf b/resources/alsa/cards/ENS1370.conf
new file mode 100644
index 0000000000000000000000000000000000000000..32e4782e8dbc54c94e9b2e6c73ac14e35c707cf6
--- /dev/null
+++ b/resources/alsa/cards/ENS1370.conf
@@ -0,0 +1,107 @@
+#
+# Configuration for the ENS1370 chip
+#
+
+<confdir:pcm/front.conf>
+
+ENS1370.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}	
+
+# default with dmix/dsnoop
+ENS1370.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+ENS1370.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface CARD
+				name "PCM 0 Output also on Line-In Jack"
+				preserve true
+				lock true
+				value true
+			}
+			{
+				name "PCM Switch"
+				preserve true
+				lock true
+				value [ false false ]
+			}
+		]
+	}
+}	
+
+<confdir:pcm/surround40.conf>
+
+ENS1370.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	master 1
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.ENS1370.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.ENS1370.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
diff --git a/resources/alsa/cards/ENS1371.conf b/resources/alsa/cards/ENS1371.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a6df42513f5a39552169029f5a0b77c5dfb550fa
--- /dev/null
+++ b/resources/alsa/cards/ENS1371.conf
@@ -0,0 +1,134 @@
+#
+# Configuration for the ENS1370 chip
+#
+
+<confdir:pcm/front.conf>
+
+ENS1371.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+ENS1371.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/rear.conf>
+
+ENS1371.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface MIXER
+				name "AC97 2ch->4ch Copy Switch"
+				lock true
+				preserve true
+				value 0
+			}
+		]
+	}
+}	
+
+<confdir:pcm/surround40.conf>
+
+ENS1371.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [ "cards.ENS1371.pcm.front.0:CARD=" $CARD ]
+			}
+			channels 2
+                }
+		{
+			pcm {
+				@func concat
+                                strings [ "cards.ENS1371.pcm.rear.0:CARD=" $CARD ]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+                                        
+<confdir:pcm/iec958.conf>
+
+ENS1371.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/ES1968.conf b/resources/alsa/cards/ES1968.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a6ee11925e9524b8a7cceda56faecfe2fa7a2106
--- /dev/null
+++ b/resources/alsa/cards/ES1968.conf
@@ -0,0 +1,12 @@
+# configuration for ESS Maestro2
+
+<confdir:pcm/front.conf>
+
+ES1968.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
diff --git a/resources/alsa/cards/Echo_Echo3G.conf b/resources/alsa/cards/Echo_Echo3G.conf
new file mode 100644
index 0000000000000000000000000000000000000000..766f13f7702856fec013f7467bd3b49806ea4e08
--- /dev/null
+++ b/resources/alsa/cards/Echo_Echo3G.conf
@@ -0,0 +1,318 @@
+#
+# Configuration for the Echo3G driver
+#
+
+<confdir:pcm/front.conf>
+Echo_Echo3G.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 0
+	subdevice 0
+}
+
+<confdir:pcm/rear.conf>
+Echo_Echo3G.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 0
+	subdevice 4
+}
+
+<confdir:pcm/center_lfe.conf>
+Echo_Echo3G.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 0
+	subdevice 2
+}
+
+<confdir:pcm/side.conf>
+Echo_Echo3G.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 0
+	subdevice 6
+}
+
+<confdir:pcm/surround40.conf>
+Echo_Echo3G.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround41.conf>
+Echo_Echo3G.pcm.surround41.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+	]
+}
+
+<confdir:pcm/surround50.conf>
+Echo_Echo3G.pcm.surround50.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/surround51.conf>
+Echo_Echo3G.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/surround71.conf>
+Echo_Echo3G.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.center_lfe.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.Echo_Echo3G.pcm.side.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+		{ slave 3 channel 0 }
+		{ slave 3 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+Echo_Echo3G.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/FM801.conf b/resources/alsa/cards/FM801.conf
new file mode 100644
index 0000000000000000000000000000000000000000..0ddf799cd029b97a196d01b1325abdc98a168283
--- /dev/null
+++ b/resources/alsa/cards/FM801.conf
@@ -0,0 +1,88 @@
+#
+# Configuration for the FM801 chip
+#
+
+<confdir:pcm/front.conf>
+
+FM801.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+FM801.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+FM801.pcm.surround40.0 "cards.FM801.pcm.front.0"
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+FM801.pcm.surround51.0 "cards.FM801.pcm.front.0"
+
+<confdir:pcm/iec958.conf>
+
+FM801.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			# {
+			#	name "IEC958 Playback Default"
+			#	value [ $AES0 $AES1 $AES2 $AES3 ]
+			# }
+			{
+				name "IEC958 Raw Data Playback Switch"
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/FWSpeakers.conf b/resources/alsa/cards/FWSpeakers.conf
new file mode 100644
index 0000000000000000000000000000000000000000..cd6fa6050b3d37fb65f970a0691f6664263724db
--- /dev/null
+++ b/resources/alsa/cards/FWSpeakers.conf
@@ -0,0 +1,26 @@
+#
+# Configuration for the LaCie Firewire speakers
+#
+
+FWSpeakers.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type plug
+	slave.pcm {
+		@func concat
+		strings [ "dmix:" $CARD ",FORMAT=S32" ]
+	}
+}
+
+<confdir:pcm/front.conf>
+
+FWSpeakers.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}
diff --git a/resources/alsa/cards/FireWave.conf b/resources/alsa/cards/FireWave.conf
new file mode 100644
index 0000000000000000000000000000000000000000..fcfc83ccfb1997ebe72484f61adba3ecd19e0609
--- /dev/null
+++ b/resources/alsa/cards/FireWave.conf
@@ -0,0 +1,51 @@
+#
+# Configuration for the Griffin FireWave Surround
+#
+
+FireWave.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type plug
+	slave.pcm {
+		@func concat
+		strings [ "dmix:" $CARD ",FORMAT=S32" ]
+	}
+}
+
+<confdir:pcm/front.conf>
+
+FireWave.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+FireWave.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable [
+		[ 1 0 0 0 0 0 ]
+		[ 0 1 0 0 0 0 ]
+		[ 0 0 0 0 1 0 ]
+		[ 0 0 0 0 0 1 ]
+		[ 0 0 1 0 0 0 ]
+		[ 0 0 0 1 0 0 ]
+	]
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+}
diff --git a/resources/alsa/cards/GUS.conf b/resources/alsa/cards/GUS.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d744c548a3f99e819d33fd989c531cec9a27cf23
--- /dev/null
+++ b/resources/alsa/cards/GUS.conf
@@ -0,0 +1,19 @@
+#
+# Configuration for the GUS soundcards
+#
+
+<confdir:pcm/front.conf>
+
+GUS.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+}	
diff --git a/resources/alsa/cards/HDA-Intel.conf b/resources/alsa/cards/HDA-Intel.conf
new file mode 100644
index 0000000000000000000000000000000000000000..fa9f6946376f91b1f9006f8ff947e69c2ddb12a8
--- /dev/null
+++ b/resources/alsa/cards/HDA-Intel.conf
@@ -0,0 +1,412 @@
+#
+# Configuration for the Intel HD audio (ICH6/ICH7)
+#
+
+<confdir:pcm/front.conf>
+
+HDA-Intel.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type softvol
+		slave.pcm {
+			type hw
+			card $CARD
+			subdevice 0
+		}
+		control {
+			name "PCM Playback Volume"
+			card $CARD
+		}
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+HDA-Intel.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dsnoop:" $CARD ]
+			}
+			control {
+				name "Digital Capture Volume"
+				card $CARD
+			}
+			min_dB -30.0
+			max_dB 30.0
+			resolution 121
+		}
+		# to avoid possible phase inversions with digital mics
+		route_policy copy
+	}
+	hint.device 0
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround40.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+<confdir:pcm/surround71.conf>
+
+HDA-Intel.pcm.surround40.0 cards.HDA-Intel.pcm.front.0
+HDA-Intel.pcm.surround51.0 cards.HDA-Intel.pcm.front.0
+HDA-Intel.pcm.surround71.0 cards.HDA-Intel.pcm.front.0
+
+<confdir:pcm/iec958.conf>
+
+HDA-Intel.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "IEC958 Playback Default"
+				index 16
+				optional true
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				index 16
+				optional true
+				value true
+				# if this element is present, skip the rest
+				skip_rest true
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				value true
+			}
+			]
+		}
+	}
+	capture.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "IEC958 Capture Switch"
+				lock true
+				preserve true
+				value true
+			}
+			]
+		}
+	}
+	hint.device 1
+}
+
+<confdir:pcm/hdmi.conf>
+
+HDA-Intel.pcm.hdmi.common {
+	@args [ CARD DEVICE CTLINDEX AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.DEVICE {
+		type integer
+	}
+	@args.CTLINDEX {
+		type integer
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device $DEVICE
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+		{
+			name "IEC958 Playback Default"
+			index $CTLINDEX
+			lock true
+			preserve true
+			value [ $AES0 $AES1 $AES2 $AES3 ]
+		}
+		{
+			name "IEC958 Playback Switch"
+			index $CTLINDEX
+			value true
+		}
+		]
+	}
+	hint.device $DEVICE
+}
+
+HDA-Intel.pcm.hdmi.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=3,"
+			"CTLINDEX=0,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.1 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=7,"
+			"CTLINDEX=1,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.2 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=8,"
+			"CTLINDEX=2,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.3 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=9,"
+			"CTLINDEX=3,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.4 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=10,"
+			"CTLINDEX=4,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.5 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=11,"
+			"CTLINDEX=5,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.6 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=12,"
+			"CTLINDEX=6,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+HDA-Intel.pcm.hdmi.7 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.HDA-Intel.pcm.hdmi.common:"
+			"CARD=" $CARD ","
+			"DEVICE=13,"
+			"CTLINDEX=7,"
+			"AES0=" $AES0 ","
+			"AES1=" $AES1 ","
+			"AES2=" $AES2 ","
+			"AES3=" $AES3
+		]
+	}
+}
+
+<confdir:pcm/modem.conf>
+
+HDA-Intel.pcm.modem.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 6
+	hint.show off
+}
diff --git a/resources/alsa/cards/HdmiLpeAudio.conf b/resources/alsa/cards/HdmiLpeAudio.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a1e493daa32497f2b479e35601eecabf62055d59
--- /dev/null
+++ b/resources/alsa/cards/HdmiLpeAudio.conf
@@ -0,0 +1,118 @@
+#
+# Configuration for the Intel HDMI/DP LPE audio
+#
+
+<confdir:pcm/hdmi.conf>
+
+HdmiLpeAudio.pcm.hdmi.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				device 0
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
+
+HdmiLpeAudio.pcm.hdmi.1 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				device 1
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
+
+HdmiLpeAudio.pcm.hdmi.2 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				device 2
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/ICE1712.conf b/resources/alsa/cards/ICE1712.conf
new file mode 100644
index 0000000000000000000000000000000000000000..db62684e25f2408044cac34f63bbe9778bbe84b9
--- /dev/null
+++ b/resources/alsa/cards/ICE1712.conf
@@ -0,0 +1,180 @@
+#
+# Configuration for the ICE1712 (Envy24) chip
+#
+
+# default with dmix & dsnoop
+ICE1712.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+}
+
+<confdir:pcm/front.conf>
+
+ICE1712.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type route
+		ttable.0.0 1
+		ttable.1.1 1
+		slave.pcm {
+			type hw
+			card $CARD
+		}
+		slave.channels 10
+	}
+	capture.pcm {
+		type route
+		ttable.0.0 1
+		ttable.1.1 1
+		slave.pcm {
+			type hw
+			card $CARD
+		}
+		slave.channels 12
+	}
+}	
+
+<confdir:pcm/surround40.conf>
+
+ICE1712.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.2 1
+	ttable.3.3 1
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	slave.channels 10
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+<confdir:pcm/surround71.conf>
+
+ICE1712.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.2 1
+	ttable.3.3 1
+	ttable.4.4 1
+	ttable.5.5 1
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	slave.channels 10
+}
+
+ICE1712.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.2 1
+	ttable.3.3 1
+	ttable.4.4 1
+	ttable.5.5 1
+	ttable.6.6 1
+	ttable.7.7 1
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	slave.channels 10
+}
+
+<confdir:pcm/iec958.conf>
+
+ICE1712.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type route
+			ttable.0.8 1
+			ttable.1.9 1
+			slave.pcm {
+				type hw
+				card $CARD
+			}
+			slave.format S32_LE
+			slave.channels 10
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface PCM
+					name "IEC958 Playback PCM Stream"
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+			]
+		}
+	}
+	capture.pcm {
+		type route
+		ttable.0.8 1
+		ttable.1.9 1
+		slave.pcm {
+			type hw
+			card $CARD
+		}
+		slave.format S32_LE
+		slave.channels 12
+	}
+}
diff --git a/resources/alsa/cards/ICE1724.conf b/resources/alsa/cards/ICE1724.conf
new file mode 100644
index 0000000000000000000000000000000000000000..61cac0132f07f0a4673684a3c4766c542cb6d84c
--- /dev/null
+++ b/resources/alsa/cards/ICE1724.conf
@@ -0,0 +1,225 @@
+#
+# Configuration for the ICE1724 (Envy24HT) chip
+#
+
+# default with dmix & dsnoop
+ICE1724.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ]
+		}
+	}
+}
+
+<confdir:pcm/front.conf>
+
+ICE1724.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+ICE1724.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	subdevice 1
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+ICE1724.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+}	
+
+<confdir:pcm/side.conf>
+
+ICE1724.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	subdevice 2
+}
+
+<confdir:pcm/surround40.conf>
+
+ICE1724.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.4 1
+	ttable.3.5 1
+	slave {
+		channels 6
+		pcm {
+			type hw
+			card $CARD
+		}
+	}
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+ICE1724.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.4 1
+	ttable.3.5 1
+	ttable.4.2 1
+	ttable.5.3 1
+	slave {
+		channels 6
+                pcm {
+			type hw
+	 		card $CARD
+		}
+	}
+}
+
+<confdir:pcm/surround71.conf>
+
+ICE1724.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.4 1
+	ttable.3.5 1
+	ttable.4.2 1
+	ttable.5.3 1
+	ttable.6.6 1
+	ttable.7.7 1
+	slave {
+		channels 8
+		pcm {
+			type hw
+			card $CARD
+		}
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+ICE1724.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+	    type linear
+	    slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface MIXER
+					name "IEC958 Output Switch"
+					lock true
+					preserve true
+					value true
+				}
+				{
+					interface PCM
+					name "IEC958 Playback Default"
+					device 1
+					lock true
+					preserve true
+					value [ $AES0 $AES1 $AES2 $AES3 ]
+				}
+			]
+		}
+	    }
+	    slave.format S32_LE
+	}
+	capture.pcm {
+	    type linear
+	    slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					interface MIXER
+					name "IEC958 Capture Switch"
+					lock true
+					preserve true
+					value true
+				}
+			]
+		}
+	    }
+	    slave.format S32_LE
+	}
+}
diff --git a/resources/alsa/cards/ICH-MODEM.conf b/resources/alsa/cards/ICH-MODEM.conf
new file mode 100644
index 0000000000000000000000000000000000000000..b96b5aaf1ad06492992f1f07b002b4e5a5b10c21
--- /dev/null
+++ b/resources/alsa/cards/ICH-MODEM.conf
@@ -0,0 +1,15 @@
+#
+# Configuration for the Intel/AMD modem controllers
+#
+
+<confdir:pcm/modem.conf>
+
+ICH-MODEM.pcm.modem.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	hint.show off
+}
diff --git a/resources/alsa/cards/ICH.conf b/resources/alsa/cards/ICH.conf
new file mode 100644
index 0000000000000000000000000000000000000000..6fc9a5a236c1276d5e718e72b85aad3d9ce29b25
--- /dev/null
+++ b/resources/alsa/cards/ICH.conf
@@ -0,0 +1,223 @@
+#
+# Configuration for the Intel ICH/ICH2/ICH3 chips
+#
+
+<confdir:pcm/front.conf>
+
+ICH.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+ICH.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+ICH.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			channels 4
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+ICH.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type route
+		ttable.0.0 1
+		ttable.1.1 1
+		ttable.2.4 1
+		ttable.3.5 1
+		ttable.4.2 1
+		ttable.5.3 1
+		slave.pcm {
+			type hooks
+			slave.pcm {
+				type hw
+				card $CARD
+				channels 6
+			}
+			hooks.0 {
+				type ctl_elems
+				hook_args [
+				{
+					name "Channel Mode"
+					preserve true
+					value "6ch"
+					lock true
+					optional true
+				}
+				# for old drivers
+				{
+					name "Line-In As Surround"
+					preserve true
+					value true
+					optional true
+				}
+				{
+					name "Mic As Center/LFE"
+					preserve true
+					value true
+					optional true
+				}
+				{
+					name "Surround Down Mix"
+					preserve true
+					value off
+					lock true
+					optional true
+				}
+				{
+					name "Center/LFE Down Mix"
+					preserve true
+					value off
+					lock true
+					optional true
+				}
+				]
+			}
+		}
+		slave.channels 6
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+ICH.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 0
+				optional true
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/ICH4.conf b/resources/alsa/cards/ICH4.conf
new file mode 100644
index 0000000000000000000000000000000000000000..64ec883d9c73b12414d42861ef710215eb208b92
--- /dev/null
+++ b/resources/alsa/cards/ICH4.conf
@@ -0,0 +1,214 @@
+#
+# Configuration for the Intel ICH4/ICH5/ICH6 chips
+#
+
+<confdir:pcm/front.conf>
+
+ICH4.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+ICH4.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+ICH4.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			channels 4
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+ICH4.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			channels 6
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "6ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Mic As Center/LFE"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			{
+				name "Center/LFE Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+ICH4.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 3
+				optional true
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/Loopback.conf b/resources/alsa/cards/Loopback.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1ae6d4536f87d72ee4ad23b1b5f6389a8fd6cacf
--- /dev/null
+++ b/resources/alsa/cards/Loopback.conf
@@ -0,0 +1,75 @@
+#
+# Configuration for the virtual loopback driver (snd-aloop)
+#
+
+<confdir:pcm/front.conf>
+
+Loopback.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+Loopback.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dsnoop:" $CARD ]
+			}
+			control {
+				name "Digital Capture Volume"
+				card $CARD
+			}
+			min_dB -30.0
+			max_dB 30.0
+			resolution 121
+		}
+		# to avoid possible phase inversions with digital mics
+		route_policy copy
+	}
+	hint.device 0
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround40.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+<confdir:pcm/surround71.conf>
+
+Loopback.pcm.surround40.0 cards.Loopback.pcm.front.0
+Loopback.pcm.surround51.0 cards.Loopback.pcm.front.0
+Loopback.pcm.surround71.0 cards.Loopback.pcm.front.0
diff --git a/resources/alsa/cards/Maestro3.conf b/resources/alsa/cards/Maestro3.conf
new file mode 100644
index 0000000000000000000000000000000000000000..94323227d7910bff9329d01e9c7c0e4cd2ca29b7
--- /dev/null
+++ b/resources/alsa/cards/Maestro3.conf
@@ -0,0 +1,38 @@
+# configuration for ESS Maestro3
+
+<confdir:pcm/front.conf>
+
+Maestro3.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+Maestro3.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			# we need to specify device and subdevice numbers
+			# for a device with multiple substreams
+			@func concat
+			strings [ "dmix:" $CARD ",0,0" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
diff --git a/resources/alsa/cards/NFORCE.conf b/resources/alsa/cards/NFORCE.conf
new file mode 100644
index 0000000000000000000000000000000000000000..64d15479291ba50d08aa780ecbf5ae26dfb5f171
--- /dev/null
+++ b/resources/alsa/cards/NFORCE.conf
@@ -0,0 +1,296 @@
+#
+# Configuration for the nVIDIA nForce/2/3
+#
+
+<confdir:pcm/front.conf>
+
+NFORCE.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+NFORCE.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+NFORCE.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			channels 4
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			]
+		}
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+NFORCE.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type route
+		ttable.0.0 1
+		ttable.1.1 1
+		ttable.2.4 1
+		ttable.3.5 1
+		ttable.4.2 1
+		ttable.5.3 1
+		slave.pcm {
+			type hooks
+			slave.pcm {
+				type hw
+				card $CARD
+				channels 6
+			}
+			hooks.0 {
+				type ctl_elems
+				hook_args [
+				{
+					name "Channel Mode"
+					preserve true
+					value "6ch"
+					lock true
+					optional true
+				}
+				# for old drivers
+				{
+					name "Line-In As Surround"
+					preserve true
+					value true
+					optional true
+				}
+				{
+					name "Mic As Center/LFE"
+					preserve true
+					value true
+					optional true
+				}
+				{
+					name "Surround Down Mix"
+					preserve true
+					value off
+					lock true
+					optional true
+				}
+				{
+					name "Center/LFE Down Mix"
+					preserve true
+					value off
+					lock true
+					optional true
+				}
+				]
+			}
+		}
+		slave.channels 6
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}
+
+<confdir:pcm/surround71.conf>
+
+NFORCE.pcm.surround71.0 {
+    @args [ CARD ]
+    @args.CARD {
+        type string
+    }
+    type softvol
+    slave.pcm {
+        type route
+        ttable.0.0 1
+        ttable.1.1 1
+        ttable.2.4 1
+        ttable.3.5 1
+        ttable.4.2 1
+        ttable.5.3 1
+        ttable.6.6 1
+        ttable.7.7 1
+        slave.pcm {
+            type hooks
+            slave.pcm {
+                type hw
+                card $CARD
+                device 0
+            }
+            hooks.0 {
+                type ctl_elems
+                hook_args [
+                {
+                    name "Channel Mode"
+                    preserve true
+                    value "8ch"
+                    lock true
+                    optional true
+                }
+                # for old drivers
+                {
+                    name "Line-In As Surround"
+                    preserve true
+                    value true
+                    optional true
+                }
+                {
+                    name "Mic As Center/LFE"
+                    preserve true
+                    value true
+                    optional true
+                }
+                {
+                    name "Surround Down Mix"
+                    preserve true
+                    value off
+                    lock true
+                    optional true
+                }
+                {
+                    name "Center/LFE Down Mix"
+                    preserve true
+                    value off
+                    lock true
+                    optional true
+                }
+                ]
+            }
+        }
+        slave.channels 8
+    }
+    control {
+        name "PCM Playback Volume"
+        card $CARD
+    }
+}
+
+<confdir:pcm/iec958.conf>
+
+NFORCE.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 0
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/PC-Speaker.conf b/resources/alsa/cards/PC-Speaker.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c82654d837fafeda3d97ca4a96dd464947e38203
--- /dev/null
+++ b/resources/alsa/cards/PC-Speaker.conf
@@ -0,0 +1,52 @@
+#
+# Configuration for PC-Speaker driver
+#
+
+<confdir:pcm/front.conf>
+
+PC-Speaker.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "Master Playback Volume"
+		card $CARD
+	}
+	min_dB -10.0
+	max_dB 20.0
+}	
+
+# default with dmix & null
+PC-Speaker.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			control {
+				name "Master Playback Volume"
+				card $CARD
+			}
+			min_dB -10.0
+			max_dB 20.0
+			slave.pcm {
+				@func concat
+				strings [ "dmix:" $CARD ]
+			}
+		}
+	}
+	capture.pcm {
+		type null
+	}
+}
+
diff --git a/resources/alsa/cards/PMac.conf b/resources/alsa/cards/PMac.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d1fdb17bfaf48078d772ce012494b349205f1360
--- /dev/null
+++ b/resources/alsa/cards/PMac.conf
@@ -0,0 +1,37 @@
+#
+# Configuration for PMac
+#
+
+<confdir:pcm/front.conf>
+
+PMac.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+PMac.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:CARD=" $CARD ",FORMAT=S16_BE" ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:CARD=" $CARD ",FORMAT=S16_BE" ]
+		}
+	}
+}
diff --git a/resources/alsa/cards/PMacToonie.conf b/resources/alsa/cards/PMacToonie.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1e0eb59cf253da6b9d4fd543b94f19ff12a7b2f4
--- /dev/null
+++ b/resources/alsa/cards/PMacToonie.conf
@@ -0,0 +1,51 @@
+#
+# Configuration for PMac Toonie
+#
+
+<confdir:pcm/front.conf>
+
+PMacToonie.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol & dsnoop
+PMacToonie.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+				strings [ "dmix:CARD=" $CARD ",FORMAT=S16_BE" ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:CARD=" $CARD ",FORMAT=S16_BE" ]
+		}
+	}
+}
diff --git a/resources/alsa/cards/PS3.conf b/resources/alsa/cards/PS3.conf
new file mode 100644
index 0000000000000000000000000000000000000000..b642f0dc18782a11211c6c6c623839af66cf7ad2
--- /dev/null
+++ b/resources/alsa/cards/PS3.conf
@@ -0,0 +1,85 @@
+#
+# Configuration for PS3
+#
+
+<confdir:pcm/front.conf>
+
+PS3.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type softvol
+	slave.pcm {
+		type hw
+		card $CARD
+		device 0
+	}
+	control {
+		name "PCM Playback Volume"
+		card $CARD
+	}
+}	
+
+# default with dmix+softvol
+PS3.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				@func concat
+                                #strings [ "dmix:CARD=" $CARD ]
+                                strings [ "dmix:CARD=" $CARD ",FORMAT=S16" ]
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+PS3.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/RME9636.conf b/resources/alsa/cards/RME9636.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e8dc5fadbaa23513872c94b2c442a135ecc053e5
--- /dev/null
+++ b/resources/alsa/cards/RME9636.conf
@@ -0,0 +1,61 @@
+#
+# Configuration for the RME9636
+#
+
+<confdir:pcm/front.conf>
+
+RME9636.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# FIXME: This configuration is not valid for double-speed rates.
+
+<confdir:pcm/iec958.conf>
+
+RME9636.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type route
+		slave {
+			pcm {
+				type hw
+				card $CARD
+			}
+			channels 18
+		}
+		ttable.0.16 1
+		ttable.1.17 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				lock true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/RME9652.conf b/resources/alsa/cards/RME9652.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1147d81065aa06fe210d812fed4fb156932aae46
--- /dev/null
+++ b/resources/alsa/cards/RME9652.conf
@@ -0,0 +1,61 @@
+#
+# Configuration for the RME9652
+#
+
+<confdir:pcm/front.conf>
+
+RME9652.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# FIXME: This configuration is not valid for double-speed rates.
+
+<confdir:pcm/iec958.conf>
+
+RME9652.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type route
+		slave {
+			pcm {
+				type hw
+				card $CARD
+			}
+			channels 26
+		}
+		ttable.0.24 1
+		ttable.1.25 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				lock true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/SB-XFi.conf b/resources/alsa/cards/SB-XFi.conf
new file mode 100644
index 0000000000000000000000000000000000000000..eb2218bfdcc704e4bf39e0e0c21539ee7f9ff8f8
--- /dev/null
+++ b/resources/alsa/cards/SB-XFi.conf
@@ -0,0 +1,109 @@
+#
+# Configuration for the SB X-Fi driver
+#
+
+<confdir:pcm/front.conf>
+
+SB-XFi.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 0
+}	
+
+<confdir:pcm/rear.conf>
+
+SB-XFi.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+	hint.device 1
+}	
+
+<confdir:pcm/center_lfe.conf>
+
+SB-XFi.pcm.center_lfe.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+	hint.device 2
+}	
+
+<confdir:pcm/side.conf>
+
+SB-XFi.pcm.side.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 3
+	hint.device 3
+}	
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround40.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+<confdir:pcm/surround71.conf>
+
+SB-XFi.pcm.surround40.0 cards.SB-XFi.pcm.front.0
+SB-XFi.pcm.surround51.0 cards.SB-XFi.pcm.front.0
+SB-XFi.pcm.surround71.0 cards.SB-XFi.pcm.front.0
+
+<confdir:pcm/iec958.conf>
+
+SB-XFi.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type asym
+	playback.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 4
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				device 4
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			]
+		}
+	}
+	hint.device 4
+}
diff --git a/resources/alsa/cards/SI7018.conf b/resources/alsa/cards/SI7018.conf
new file mode 100644
index 0000000000000000000000000000000000000000..02b8fc877ff362c0807ef45dc109536b157c31b6
--- /dev/null
+++ b/resources/alsa/cards/SI7018.conf
@@ -0,0 +1,169 @@
+#
+# Configuration for the SI7018 chip
+#
+# This configuration does not reflect hardware.
+#
+
+<confdir:pcm/front.conf>
+
+SI7018.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	chmap [ "UNKNOWN" "FL,FR" ]
+}	
+
+<confdir:pcm/rear.conf>
+
+SI7018.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+        type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "RL,RR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "PCM Playback Volume"
+				preserve true
+				lock true
+				value [ 24 24 ]
+			}
+		]
+	}
+}	
+
+<confdir:pcm/surround40.conf>
+
+SI7018.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.SI7018.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.SI7018.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+SI7018.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.SI7018.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.SI7018.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.SI7018.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+		{ slave 2 channel 0 }
+		{ slave 2 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+SI7018.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+				device 1
+				lock true
+				preserve true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/TRID4DWAVENX.conf b/resources/alsa/cards/TRID4DWAVENX.conf
new file mode 100644
index 0000000000000000000000000000000000000000..717b14087279c06f95c678230e5899f10708d89f
--- /dev/null
+++ b/resources/alsa/cards/TRID4DWAVENX.conf
@@ -0,0 +1,131 @@
+#
+# Configuration for the Trident 4D-Wave NX chip
+#
+
+<confdir:pcm/front.conf>
+
+TRID4DWAVENX.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	chmap [ "UNKNOWN" "FL,FR" ]
+}	
+
+<confdir:pcm/rear.conf>
+
+TRID4DWAVENX.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		chmap [ "UNKNOWN" "RL,RR" ]
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Rear Path"
+				lock true
+				preserve true
+				value true
+			}
+			{
+				name "PCM Front Playback Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				preserve true
+				value 0
+			}
+			{
+				name "PCM Reverb Playback Volume"
+				index { @func private_pcm_subdevice }
+				lock true
+				preserve true
+				value 127
+			}
+		]
+	}
+}	
+
+<confdir:pcm/surround40.conf>
+
+TRID4DWAVENX.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.TRID4DWAVENX.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.TRID4DWAVENX.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+TRID4DWAVENX.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 2
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+				device 2
+				lock true
+				preserve true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/USB-Audio.conf b/resources/alsa/cards/USB-Audio.conf
new file mode 100644
index 0000000000000000000000000000000000000000..9b64af3c0da9305d5f1173e9db525bbaad566c71
--- /dev/null
+++ b/resources/alsa/cards/USB-Audio.conf
@@ -0,0 +1,498 @@
+#
+#  USB-Audio.conf - configuration for USB Audio devices
+#
+#
+#  DO NO EDIT; this is an internal ALSA file.
+#  If you want to add your own definitions, put them into /etc/asound.conf or
+#  ~/.asoundrc, with "cards." before the "USB-Audio", e.g.:
+#
+#  cards.USB-Audio.pcm.use_dmix."NoiseBlaster 3000" no
+#
+#  If your device requires such a definition to work correctly, please report it
+#  to <alsa-devel@alsa-project.org>.
+
+
+# If a device has sample formats not supported by dmix, dmix can be disabled
+# here.
+USB-Audio.pcm.use_dmix {
+	"AudioPhile" no    # uses big-endian 24-bit samples
+	"Audiophile USB (tm)" no
+}
+
+# If a device does not have a four-channel mode for the front/rear outputs,
+# other modes can be selected here.
+# six_channels       - for devices that route the last two of the four channels
+#                      to the center/LFE outputs
+# two_stereo_devices - for devices that have two stereo audio interfaces
+USB-Audio.pcm.surround40_type {
+	"AudioPhile" two_stereo_devices
+	"Audiophile USB (tm)" two_stereo_devices
+	"OmniStudio" two_stereo_devices
+	"Quattro" two_stereo_devices
+	"SB Audigy 2 NX" six_channels
+	"USB AudioSport Quattro (tm)" two_stereo_devices
+}
+
+# If a device does not use the first PCM device for digital data, the device
+# number for the iec958 device can be changed here.
+USB-Audio.pcm.iec958_device {
+	# "NoiseBlaster 3000" 42
+	"USB Sound Blaster HD" 1
+	"Xonar U7" 1
+	"ASUS XONAR U5" 1
+	"XONAR U5" 1
+	"XONAR SOUND CARD" 1
+	"Xonar SoundCard" 2
+	
+	# The below don't have digital in/out, so prevent them from being opened.
+	"Andrea PureAudio USB-SA Headset" 999
+	"Blue Snowball" 999
+	"C-Media USB Headphone Set" 999
+	"HP Digital Stereo Headset" 999
+	"GN 9330" 999
+	"Logitech Speaker Lapdesk N700" 999
+	"Logitech G35 Headset" 999
+	"Logitech USB Headset" 999
+	"Logitech USB Headset H540" 999
+	"Logitech Wireless Headset" 999
+	"Plantronics GameCom 780" 999
+	"Plantronics USB Headset" 999
+	"Plantronics Wireless Audio" 999
+	"SB WoW Headset" 999
+	"Scarlett 2i2 USB" 999
+	"Scarlett 2i4 USB" 999
+	"Sennheiser USB headset" 999
+	"SWTOR Gaming Headset by Razer" 999
+	"ThinkStation P620 Main" 999
+	"ThinkStation P620 Rear" 999
+	"Thunderbolt Dock Audio Headset" 999
+	"Thunderbolt Dock Audio Module" 999
+	"USB Device 0x46d_0x821" 999
+	"USB Device 0x46d_0x992" 999
+	"WD15 Dock" 999
+	"WD19 Dock" 999
+}
+
+# Second iec958 device number, if any.
+USB-Audio.pcm.iec958_2_device {
+	"PHIREE U2" 1  # 0 = PCM S/PDIF, 1 = non-PCM S/PDIF
+	"PHIREE U2SX" 1  # 0 = PCM S/PDIF, 1 = non-PCM S/PDIF
+}
+
+
+# If a device requires non-standard definitions for front, default, surround40,
+# surround51, surround71 or iec958, they can be defined here.
+
+# M-Audio AudioPhile USB:
+# device 0: analog output, digital input
+# device 1: digital output, analog input
+USB-Audio."AudioPhile".pcm.default "cards.USB-Audio.Audiophile USB (tm).pcm.default"
+USB-Audio."Audiophile USB (tm)".pcm.default {
+	@args [ CARD ]
+	@args.CARD { type string }
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type hw
+			card $CARD
+			device 0
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:DEV=1,CARD=" $CARD ]
+		}
+	}
+}
+USB-Audio."AudioPhile".pcm.iec958 "cards.USB-Audio.Audiophile USB (tm).pcm.iec958"
+USB-Audio."Audiophile USB (tm)".pcm.iec958 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	type asym
+	playback.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	capture.pcm {
+		type hw
+		card $CARD
+		device 0
+	}
+}
+
+# For this card we can (and must to get IEC61937) set AES bits
+USB-Audio."MicroII".pcm.iec958 "cards.USB-Audio.Audio Advantage MicroII.pcm.iec958"
+USB-Audio."Audio Advantage MicroII".pcm.iec958 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value 1
+			}
+		]
+	}
+}
+
+################################################################################
+
+<confdir:pcm/front.conf>
+
+USB-Audio.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD { type string }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.front:CARD=" $CARD
+		]
+	}
+	default {
+		# We could use softvol, but the driver might have guessed a
+		# wrong name for the real volume control.
+		type hw
+		card $CARD
+		device 0
+	}
+}
+
+USB-Audio.pcm.default {
+	@args [ CARD ]
+	@args.CARD { type string }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.default:CARD=" $CARD
+		]
+	}
+	default {
+		type asym
+		playback.pcm {
+			type plug
+			slave.pcm {
+				@func refer
+				name {
+					@func concat
+					strings [
+						"cards.USB-Audio.pcm.default_playback_dmix_"
+						{
+							@func refer
+							name {
+								@func concat
+								strings [
+									"cards.USB-Audio.pcm.use_dmix."
+									{ @func card_name card $CARD }
+								]
+							}
+							default yes
+						}
+						":CARD=" $CARD
+					]
+				}
+			}
+		}
+		capture.pcm {
+			type plug
+			slave.pcm {
+				@func concat
+				strings [ "dsnoop:" $CARD ]
+			}
+		}
+	}
+}
+
+USB-Audio.pcm.default_playback_dmix_yes {
+	@args [ CARD ]
+	@args.CARD { type string }
+	@func concat
+	strings [ "dmix:" $CARD ]
+}
+
+USB-Audio.pcm.default_playback_dmix_no {
+	@args [ CARD ]
+	@args.CARD { type string }
+	type hw
+	card $CARD
+	device 0
+}
+
+<confdir:pcm/surround40.conf>
+
+USB-Audio.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD { type string }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.surround40:CARD=" $CARD
+		]
+	}
+	default {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards.USB-Audio.pcm.surround40_"
+				{
+					@func refer
+					name {
+						@func concat
+						strings [
+							"cards.USB-Audio.pcm.surround40_type."
+							{ @func card_name card $CARD }
+						]
+					}
+					default default
+				}
+				":CARD=" $CARD
+			]
+		}
+	}
+}
+
+USB-Audio.pcm.surround40_default {
+	@args [ CARD ]
+	@args.CARD { type string }
+	type hw
+	card $CARD
+	device 0
+}
+
+USB-Audio.pcm.surround40_six_channels {
+	@args [ CARD ]
+	@args.CARD { type string }
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.4 1
+	ttable.3.5 1
+	slave {
+		pcm {
+			type hw
+			card $CARD
+			device 0
+		}
+		channels 6
+	}
+}
+
+USB-Audio.pcm.surround40_two_stereo_devices {
+	@args [ CARD ]
+	@args.CARD { type string }
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.2 1
+	ttable.3.3 1
+	slave.pcm {
+		type multi
+		slaves {
+			a {
+				pcm {
+					type hw
+					card $CARD
+					device 0
+				}
+				channels 2
+			}
+			b {
+				pcm {
+					type hw
+					card $CARD
+					device 1
+				}
+				channels 2
+			}
+		}
+		bindings [
+			{ slave a channel 0 }
+			{ slave a channel 1 }
+			{ slave b channel 0 }
+			{ slave b channel 1 }
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+USB-Audio.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD { type string }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.surround51:CARD=" $CARD
+		]
+	}
+	default {
+		type route
+		ttable.0.0 1
+		ttable.1.1 1
+		ttable.2.4 1
+		ttable.3.5 1
+		ttable.4.2 1
+		ttable.5.3 1
+		slave {
+			pcm {
+				type hw
+				card $CARD
+				device 0
+			}
+			channels 6
+		}
+	}
+}
+
+<confdir:pcm/surround71.conf>
+
+USB-Audio.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD { type string }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.surround71:CARD=" $CARD
+		]
+	}
+	default {
+		type route
+		ttable.0.0 1
+		ttable.1.1 1
+		ttable.2.4 1
+		ttable.3.5 1
+		ttable.4.2 1
+		ttable.5.3 1
+		ttable.6.6 1
+		ttable.7.7 1
+		slave {
+			pcm {
+				type hw
+				card $CARD
+				device 0
+			}
+			channels 8
+		}
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+USB-Audio.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.iec958:CARD=" $CARD
+			",AES0=" $AES0 ",AES1=" $AES1 ",AES2=" $AES2 ",AES3=" $AES3
+		]
+	}
+	default {
+		# FIXME: we cannot set the AES parameters
+		type hw
+		card $CARD
+		device {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"cards.USB-Audio.pcm.iec958_device."
+					{ @func card_name card $CARD }
+				]
+			}
+			default 0
+		}
+	}
+}
+
+USB-Audio.pcm.iec958.1 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD { type string }
+	@args.AES0 { type integer }
+	@args.AES1 { type integer }
+	@args.AES2 { type integer }
+	@args.AES3 { type integer }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.iec958_2:CARD=" $CARD
+			",AES0=" $AES0 ",AES1=" $AES1 ",AES2=" $AES2 ",AES3=" $AES3
+		]
+	}
+	default {
+		# FIXME: we cannot set the AES parameters
+		type hw
+		card $CARD
+		device {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"cards.USB-Audio.pcm.iec958_2_device."
+					{ @func card_name card $CARD }
+				]
+			}
+			default 999
+		}
+	}
+}
+
+# vim: ft=alsaconf
diff --git a/resources/alsa/cards/VIA686A.conf b/resources/alsa/cards/VIA686A.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e4a06f236591f19c92ef11ecfac1be9fcff6aff0
--- /dev/null
+++ b/resources/alsa/cards/VIA686A.conf
@@ -0,0 +1,89 @@
+#
+# Configuration for the VIA686A chip
+#
+# SPDIF support is not complete - it might not work, especially with AC3
+# passthru mode...
+#
+
+<confdir:pcm/front.conf>
+
+VIA686A.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+VIA686A.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+VIA686A.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 0
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/VIA8233.conf b/resources/alsa/cards/VIA8233.conf
new file mode 100644
index 0000000000000000000000000000000000000000..9ad321f713a990df9c91660397a08c3669bab20d
--- /dev/null
+++ b/resources/alsa/cards/VIA8233.conf
@@ -0,0 +1,201 @@
+#
+# Configuration for the VIA8233/VIA8233C/VIA8235 chip with 4/6 multi-channel support
+#
+
+<confdir:pcm/front.conf>
+
+VIA8233.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with softvol/dsnoop
+# VIA8233 supports multi-playback
+VIA8233.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				type hw
+				card $CARD
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+VIA8233.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+		channels 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+VIA8233.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+		channels 6
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "6ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Mic As Center/LFE"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			{
+				name "Center/LFE Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+VIA8233.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		subdevice 3
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 3
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+			{
+				name "IEC958 Output Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/VIA8233A.conf b/resources/alsa/cards/VIA8233A.conf
new file mode 100644
index 0000000000000000000000000000000000000000..679fccf3d06f6afbff5ecaf4a5ce616cc2eeb6ac
--- /dev/null
+++ b/resources/alsa/cards/VIA8233A.conf
@@ -0,0 +1,205 @@
+#
+# Configuration for the VIA8233A chip with 4/6 multi-channel support
+#
+
+<confdir:pcm/front.conf>
+
+VIA8233A.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with dmix/dsnoop
+VIA8233A.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+VIA8233A.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		channels 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Swap Surround Slot"
+				lock true
+				preserve true
+				value false
+				optional true
+			}
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+VIA8233A.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		channels 6
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Swap Surround Slot"
+				lock true
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Channel Mode"
+				preserve true
+				value "6ch"
+				lock true
+				optional true
+			}
+			# for old drivers
+			{
+				name "Line-In As Surround"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Mic As Center/LFE"
+				preserve true
+				value true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+			{
+				name "Center/LFE Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+VIA8233A.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 3
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+			{
+				name "IEC958 Output Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/VIA8237.conf b/resources/alsa/cards/VIA8237.conf
new file mode 100644
index 0000000000000000000000000000000000000000..29d8e00f6601f7f04151cccce3b57d8f79032cd9
--- /dev/null
+++ b/resources/alsa/cards/VIA8237.conf
@@ -0,0 +1,191 @@
+#
+# Configuration for the VIA8237 chip with 4/6 multi-channel support
+#
+
+<confdir:pcm/front.conf>
+
+VIA8237.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+# default with softvol/dsnoop
+# VIA8237 supports multi-playback
+VIA8237.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			type softvol
+			slave.pcm {
+				type hw
+				card $CARD
+			}
+			control {
+				name "PCM Playback Volume"
+				card $CARD
+			}
+		}
+	}
+	capture.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dsnoop:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/surround40.conf>
+
+VIA8237.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+		channels 4
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "Channel Mode"
+				preserve true
+				value "4ch"
+				lock true
+				optional true
+			}
+			{
+				name "Surround Down Mix"
+				preserve true
+				value off
+				lock true
+				optional true
+			}
+		]
+	}
+}
+
+<confdir:pcm/surround21.conf>
+<confdir:pcm/surround41.conf>
+<confdir:pcm/surround50.conf>
+<confdir:pcm/surround51.conf>
+
+VIA8237.pcm.surround51.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.4 1
+	ttable.3.5 1
+	ttable.4.2 1
+	ttable.5.3 1
+	slave.pcm {
+		type hooks
+		slave.pcm {
+			type hw
+			card $CARD
+			device 1
+			channels 6
+		}
+		hooks.0 {
+			type ctl_elems
+			hook_args [
+				{
+					name "Channel Mode"
+					preserve true
+					value "6ch"
+					lock true
+					optional true
+				}
+				{
+					name "Surround Down Mix"
+					preserve true
+					value off
+					lock true
+					optional true
+				}
+				{
+					name "Center/LFE Down Mix"
+					preserve true
+					value off
+					lock true
+					optional true
+				}
+			]
+		}
+	}
+	slave.channels 6
+}
+
+<confdir:pcm/iec958.conf>
+
+VIA8237.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		subdevice 3
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback AC97-SPSA"
+				lock true
+				preserve true
+				value 3
+			}
+			{
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value true
+			}
+			{
+				name "IEC958 Output Switch"
+				lock true
+				preserve true
+				value true
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/VX222.conf b/resources/alsa/cards/VX222.conf
new file mode 100644
index 0000000000000000000000000000000000000000..3385f25bde98ff39a165a476479f5d97361de474
--- /dev/null
+++ b/resources/alsa/cards/VX222.conf
@@ -0,0 +1,61 @@
+#
+# Configuration for Digigram VX222
+#
+
+<confdir:pcm/front.conf>
+
+VX222.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/iec958.conf>
+
+VX222.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/VXPocket.conf b/resources/alsa/cards/VXPocket.conf
new file mode 100644
index 0000000000000000000000000000000000000000..fe44ff53a83d3430c7617cc9e6ce8b6686934398
--- /dev/null
+++ b/resources/alsa/cards/VXPocket.conf
@@ -0,0 +1,61 @@
+#
+# Configuration for Digigram VXpocket
+#
+
+<confdir:pcm/front.conf>
+
+VXPocket.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/iec958.conf>
+
+VXPocket.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/VXPocket440.conf b/resources/alsa/cards/VXPocket440.conf
new file mode 100644
index 0000000000000000000000000000000000000000..197c2d6c5efd0716379d692161d352208ae8df85
--- /dev/null
+++ b/resources/alsa/cards/VXPocket440.conf
@@ -0,0 +1,110 @@
+#
+# Configuration for Digigram VXpocket440
+#
+
+<confdir:pcm/front.conf>
+
+VXPocket440.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+VXPocket440.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 1
+}
+
+<confdir:pcm/surround40.conf>
+
+VXPocket440.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	master 1
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.VXPocket440.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.VXPocket440.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+VXPocket440.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				interface PCM
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+			{
+				# for compatibility with older drivers
+				name "IEC958 Playback Default"
+				lock true
+				preserve true
+				optional true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/YMF744.conf b/resources/alsa/cards/YMF744.conf
new file mode 100644
index 0000000000000000000000000000000000000000..84dbcbec3e8aa62706007795eec872a86a183006
--- /dev/null
+++ b/resources/alsa/cards/YMF744.conf
@@ -0,0 +1,108 @@
+#
+# Configuration for the YMF744 chip
+#
+
+<confdir:pcm/front.conf>
+
+YMF744.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}	
+
+<confdir:pcm/rear.conf>
+
+YMF744.pcm.rear.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+	device 2
+}	
+
+<confdir:pcm/surround40.conf>
+
+YMF744.pcm.surround40.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type multi
+	slaves [
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.YMF744.pcm.front.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+		{
+			pcm {
+				@func concat
+				strings [
+					"cards.YMF744.pcm.rear.0:CARD=" $CARD
+				]
+			}
+			channels 2
+		}
+	]
+	bindings [
+		{ slave 0 channel 0 }
+		{ slave 0 channel 1 }
+		{ slave 1 channel 0 }
+		{ slave 1 channel 1 }
+	]
+}
+
+<confdir:pcm/iec958.conf>
+
+YMF744.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type hooks
+	slave.pcm {
+		type hw
+		card $CARD
+		device 1
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+			{
+				name "IEC958 Playback Switch"
+				lock true
+				preserve true
+				value 1
+			}
+			{
+				interface PCM
+				name "IEC958 Playback PCM Stream"
+				device 1
+				lock true
+				preserve true
+				value [ $AES0 $AES1 $AES2 $AES3 ]
+			}
+		]
+	}
+}
diff --git a/resources/alsa/cards/aliases.conf b/resources/alsa/cards/aliases.conf
new file mode 100644
index 0000000000000000000000000000000000000000..18a920f41e46adea340640e0bcc82de82190d62c
--- /dev/null
+++ b/resources/alsa/cards/aliases.conf
@@ -0,0 +1,63 @@
+#
+#  Define aliases for various drivers
+#
+
+YMF724 cards.YMF744
+YMF724F cards.YMF744
+YMF740 cards.YMF744
+YMF740C cards.YMF744
+YMF754 cards.YMF744
+CMIPCI cards.CMI8338
+CMI8738 cards.CMI8338
+CMI8738-SWIEC cards.CMI8338-SWIEC
+CMI8738-MC4 cards.CMI8738-MC6
+'E-mu APS' cards.EMU10K1
+'GUS MAX' cards.GUS
+'GUS ACE' cards.GUS
+'GUS Extreme' cards.GUS
+'AMD InterWave' cards.GUS
+'Dynasonic 3-D' cards.GUS
+'InterWave STB' cards.GUS
+au8810 cards.AU8810
+au8820 cards.AU8820
+au8830 cards.AU8830
+Prodigy71 cards.Aureon71
+Prodigy71LT cards.Aureon71
+Prodigy71HIFI cards.Aureon71
+Aureon71Univ cards.Aureon71
+VIA82XX-MODEM cards.ICH-MODEM
+'MPU-401 UART' cards.MPU-401
+'VX222/Old' cards.VX222
+'VX222/v2' cards.VX222
+'VX222/Mic' cards.VX222
+'CMI8330/C3D' cards.CMI8330
+'SB AWE' cards.SBAWE
+'SB Pro' cards.SBPro
+'PMac Burgundy' cards.PMac
+'PMac DACA' cards.PMac
+'PMac Tumbler' cards.PMac
+'PMac Snapper' cards.PMac
+'PMac Screamer' cards.PMac
+'PMac AWACS' cards.PMac
+'PMac Toonie' cards.PMacToonie
+AppleOnbdAudio cards.PMacToonie
+'USB US-X2Y' cards.US-X2Y
+'Serial MIDI' cards.SerialMIDI
+'Prodif Plus' cards.ProdifPlus
+ESM1 cards.ES1968
+ES1978 cards.ES1968
+Allegro cards.Maestro3
+Canyon3D-2 cards.Maestro3
+Azalia cards.HDA-Intel
+aaci-pl041 cards.AACI
+AV66 cards.CMI8788
+AV100 cards.CMI8788
+AV200 cards.CMI8788
+CMI8786 cards.CMI8788
+CMI8787 cards.CMI8788
+pistachio cards.pistachio-card
+VC4-HDMI cards.vc4-hdmi
+
+<confdir:pcm/default.conf>
+<confdir:pcm/dmix.conf>
+<confdir:pcm/dsnoop.conf>
diff --git a/resources/alsa/cards/pistachio-card.conf b/resources/alsa/cards/pistachio-card.conf
new file mode 100644
index 0000000000000000000000000000000000000000..59cd920e0159ff30bace3e8ba7f9ef24878cfa61
--- /dev/null
+++ b/resources/alsa/cards/pistachio-card.conf
@@ -0,0 +1,58 @@
+#
+# Configuration for the pistachio chip.
+#
+# The data sheet of the chip and technical reference manual can be 
+found at 
+https://docs.creatordev.io/ci40/guides/hardwaredocs/cXT200_datasheet2.p
+df # and 
+https://docs.creatordev.io/ci40/guides/hardwaredocs/MIPS_Creator_cXT200_Technical_Reference_Manual_1.0.112.pdf.
+#
+# The list of hardware devices is as per below:
+#
+#  root@OpenWrt:/# arecord -l
+# **** List of CAPTURE Hardware Devices **** card 0: pistachiocard [pistachio-card], device 1: pistachio-spdif-in snd-soc-dummy-dai-1 []
+#   Subdevices: 1/1
+#   Subdevice #0: subdevice #0
+# card 0: pistachiocard [pistachio-card], device 4: pistachio-i2s-in-0 snd-soc-dummy-dai-4 []
+#   Subdevices: 1/1
+#   Subdevice #0: subdevice #0
+#
+# root@OpenWrt:/# aplay -l
+# **** List of PLAYBACK Hardware Devices **** card 0: pistachiocard [pistachio-card], device 0: pistachio-spdif-out snd-soc-dummy-dai-0 []
+#   Subdevices: 1/1
+#   Subdevice #0: subdevice #0
+# card 0: pistachiocard [pistachio-card], device 2: pistachio-parallel-out pistachio_internal_dac-2 []
+#   Subdevices: 1/1
+#   Subdevice #0: subdevice #0
+# card 0: pistachiocard [pistachio-card], device 3: pistachio-i2s-out snd-soc-dummy-dai-3 []
+#   Subdevices: 1/1
+#   Subdevice #0: subdevice #0
+#
+
+pistachio-card.pcm.default{
+        @args [ CARD ]
+        @args.CARD {
+                type string
+                default "pistachio"
+        }
+        @args.DEVICE {
+                type integer
+                default 2
+        }
+
+        type asym
+        capture.pcm {
+                type multi
+                slaves.a.pcm "hw:0,4"
+                slaves.a.channels 12
+                bindings.0.slave a
+                bindings.0.channel 4
+                bindings.1.slave a
+                bindings.1.channel 5
+        }
+
+        playback.pcm {
+                type hw
+                card $CARD
+                device $DEVICE
+
diff --git a/resources/alsa/cards/vc4-hdmi.conf b/resources/alsa/cards/vc4-hdmi.conf
new file mode 100644
index 0000000000000000000000000000000000000000..027804a145d1ed9e4fe33dbb5fa7ef278230c328
--- /dev/null
+++ b/resources/alsa/cards/vc4-hdmi.conf
@@ -0,0 +1,64 @@
+#
+# Configuration for the VC4-HDMI sound card using software IEC958
+# subframe conversion
+#
+
+<confdir:pcm/front.conf>
+
+vc4-hdmi.pcm.front.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type hw
+	card $CARD
+}
+
+# default with dmix
+vc4-hdmi.pcm.default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type asym
+	playback.pcm {
+		type plug
+		slave.pcm {
+			@func concat
+			strings [ "dmix:" $CARD ]
+		}
+	}
+}
+
+<confdir:pcm/iec958.conf>
+
+vc4-hdmi.pcm.iec958.0 {
+	@args [ CARD AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+	}
+	@args.AES0 {
+		type integer
+	}
+	@args.AES1 {
+		type integer
+	}
+	@args.AES2 {
+		type integer
+	}
+	@args.AES3 {
+		type integer
+	}
+	type iec958
+	slave {
+		format IEC958_SUBFRAME_LE
+		pcm {
+			type plug
+			slave.pcm {
+				type hw
+				card $CARD
+			}
+		}
+	}
+	status [ $AES0 $AES1 $AES2 $AES3 ]
+}
diff --git a/resources/alsa/init/00main b/resources/alsa/init/00main
new file mode 100644
index 0000000000000000000000000000000000000000..21fd8af85b01b9e4f3a0c2e9bcd43b6c75c34380
--- /dev/null
+++ b/resources/alsa/init/00main
@@ -0,0 +1,49 @@
+# This is toplevel configuration for for 'alsactl init'.
+# See 'man alsactl_init' for syntax.
+
+# set root device directory in sysfs for soundcard for ATTR{} command
+CONFIG{sysfs_device}="/class/sound/card$cardinfo{card}/device"
+ACCESS!="$sysfsroot$config{sysfs_device}", \
+	CONFIG{sysfs_device}="/class/sound/controlC$cardinfo{card}/device"
+
+# test for extra commands
+ENV{CMD}=="help", INCLUDE="help", GOTO="00main_end"
+ENV{CMD}=="info", INCLUDE="info", GOTO="00main_end"
+ENV{CMD}=="default", INCLUDE="default", GOTO="00main_end"
+ENV{CMD}=="test", INCLUDE="test", GOTO="00main_end"
+ENV{CMD}=="*", ERROR="Unknown command '$env{CMD}'\n", GOTO="00main_end"
+
+# include files with real configuration
+#
+# steps are:
+#   1) look for preinit subdirectory and parse all files in it
+#   2) if RESULT=="skip", skip ALSA standard configuration files
+#   3) do ALSA standard configuration
+#   4) look for postinit subdirectory and parse all files in it
+#   5) if RESULT!="true", initialize hardware using a guess method,
+#      print an error message and return with exit code 99
+#   6) return with exit code 0 (success)
+#
+
+RESULT="unknown"
+ACCESS=="preinit", INCLUDE="preinit"
+RESULT=="skip", GOTO="init_end"
+
+# real ALSA configuration database
+CARDINFO{driver}=="HDA-Intel", INCLUDE="hda", GOTO="init_end"
+CARDINFO{driver}=="CA0106", INCLUDE="ca0106", GOTO="init_end"
+CARDINFO{driver}=="Test", INCLUDE="test", GOTO="init_end"
+
+LABEL="init_end"
+ACCESS=="postinit", INCLUDE="postinit"
+RESULT=="true", GOTO="00main_end"
+ERROR="Found hardware: \"$cardinfo{driver}\" \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}\" \"$attr{subsystem_device}\"\n"
+ERROR="Hardware is initialized using a generic method\n"
+INCLUDE="default"
+EXIT="99"
+
+#
+# label identifying end of main file
+#
+
+LABEL="00main_end"
diff --git a/resources/alsa/init/ca0106 b/resources/alsa/init/ca0106
new file mode 100644
index 0000000000000000000000000000000000000000..45fc8330a68e66b626665e90e7309fc46c94ca17
--- /dev/null
+++ b/resources/alsa/init/ca0106
@@ -0,0 +1,31 @@
+# Configuration for CA0106 driver
+
+CTL{reset}="mixer"
+CTL{name}="Master Playback Volume", CTL{values}="-20dB"
+CTL{name}="Master Playback Switch", CTL{values}="on"
+CTL{name}="Analog Front Playback Volume", CTL{values}="0dB"
+CTL{name}="Analog Front Playback Switch", CTL{values}="on"
+CTL{name}="Analog Rear Playback Volume", CTL{values}="0dB"
+CTL{name}="Analog Rear Playback Switch", CTL{values}="on"
+CTL{name}="Analog Center/LFE Playback Volume", CTL{values}="0dB"
+CTL{name}="Analog Center/LFE Playback Switch", CTL{values}="on"
+CTL{name}="Analog Side Playback Volume", CTL{values}="0dB"
+CTL{name}="Analog Side Playback Switch", CTL{values}="on"
+CTL{name}="IEC958 Front Playback Volume", CTL{values}="0dB"
+CTL{name}="IEC958 Rear Playback Volume", CTL{values}="0dB"
+CTL{name}="IEC958 Center/LFE Playback Volume", CTL{values}="0dB"
+# capture
+CTL{name}="Analog Source Capture Enum", CTL{value}="Mic"
+CTL{name}="Mic Capture Volume", CTL{values}="6dB"
+CTL{name}="Shared Mic/Line in Capture Switch", CTL{values}="Mic in"
+
+# some variants have also AC97 mixer
+
+CTL{reset}="mixer"
+CTL{name}="AC97 Line Capture Volume",PROGRAM!="__ctl_search",GOTO="ac97_end"
+CTL{name}="Analog Source Capture Enum", CTL{value}="AC97 in"
+CTL{name}="AC97 Mic Capture Switch", "on"
+CTL{name}="AC97 Mic Capture Value", "6dB"
+LABEL="ac97_end"
+
+RESULT="true", EXIT="return"
diff --git a/resources/alsa/init/default b/resources/alsa/init/default
new file mode 100644
index 0000000000000000000000000000000000000000..1c84f3e859e72400c52d42f1e90294da3e1fc0e1
--- /dev/null
+++ b/resources/alsa/init/default
@@ -0,0 +1,284 @@
+#
+# Default ALSA volume levels and setting when initialization database fails.
+#
+# Basic rules are:
+#  - keep volumes at minimal level, but sound should be hearable
+#  - enable standard outputs for playback and main microphone for recording
+#
+
+# **************************************************************************
+# playback
+# **************************************************************************
+
+ENV{ppercent}:="75%"
+ENV{cpercent}:="75%"
+ENV{pvolume}:="-20dB"
+ENV{cvolume}:="12dB"
+ENV{has_pmaster_vol}:="false"
+
+CTL{reset}="mixer"
+CTL{name}="Playback Volume",CTL{do_search}=="1", \
+  CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+CTL{name}="Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Playback Volume",CTL{do_search}=="1", \
+  ENV{has_pmaster_vol}:="true", \
+  CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+CTL{name}="Master Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Front Playback Volume",CTL{do_search}=="1", \
+  ENV{has_pmaster_vol}:="true", \
+  CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+CTL{name}="Master Front Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Digital Playback Volume",CTL{do_search}=="1", \
+  CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+CTL{name}="Master Digital Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Line Out Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn line out volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Line Out Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Front Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn front volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Front Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Surround Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn front volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Surround Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Center Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn front volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Center Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="LFE Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn front volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="LFE Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Headphone Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn headphone volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Headphone Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Headphone Playback Volume",CTL{index}="1",PROGRAM!="__ctl_search",\
+  GOTO=""
+# if master volume control is present, turn headphone volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Headphone Playback Switch",CTL{index}="1",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Speaker Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn speaker volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Speaker Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Front Speaker Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn speaker volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Front Speaker Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Surround Speaker Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn speaker volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Surround Speaker Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Center Speaker Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn speaker volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="Center Speaker Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="LFE Speaker Playback Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn speaker volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+LABEL=""
+CTL{name}="LFE Speaker Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="PC Speaker Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="$env{pvolume}",RESULT!="0",CTL{values}="$env{ppercent}"
+CTL{name}="PC Speaker Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="PCM Playback Volume",PROGRAM!="__ctl_search", \
+ CTL{name}="PCM Volume",PROGRAM!="__ctl_search", GOTO=""
+# if master volume control is present, turn PCM volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+# exception - some HDA codecs have shifted dB range
+CTL{dBmin}=="-34.50dB",CTL{dBmax}=="12.00dB",CTL{write}=="0dB",GOTO=""
+CTL{dBmin}=="-30.00dB",CTL{dBmax}=="0dB",CTL{write}=="0dB",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="75%"
+LABEL=""
+CTL{name}="PCM Playback Switch",CTL{do_search}=="1", CTL{values}="on"
+CTL{name}="PCM Switch",CTL{do_search}=="1",CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="PCM Playback Volume",CTL{index}="1",PROGRAM!="__ctl_search", \
+  CTL{name}="PCM Volume",PROGRAM!="__ctl_search",GOTO=""
+# if master volume control is present, turn PCM volume to max
+ENV{has_pmaster_vol}=="true",CTL{write}=="0dB",GOTO=""
+ENV{has_pmaster_vol}=="true",CTL{write}=="100%",GOTO=""
+# exception - some HDA codecs have shifted dB range
+CTL{dBmin}=="-34.50dB",CTL{dBmax}=="12.00dB",CTL{write}=="0dB",GOTO=""
+CTL{dBmin}=="-30.00dB",CTL{dBmax}=="0dB",CTL{write}=="0dB",GOTO=""
+CTL{write}!="$env{pvolume}",CTL{values}="75%"
+LABEL=""
+CTL{name}="PCM Playback Switch",CTL{index}="1",CTL{do_search}=="1", \
+  CTL{values}="on"
+CTL{name}="PCM Switch",CTL{index}="1",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="DAC Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="$env{pvolume}",RESULT!="0",CTL{values}="$env{ppercent}"
+CTL{name}="DAC Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Synth Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="$env{pvolume}",RESULT!="0",CTL{values}="$env{ppercent}"
+CTL{name}="Synth Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Wave Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="100%"
+CTL{name}="Wave Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Music Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="100%"
+CTL{name}="Music Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="CD Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="0%"
+CTL{name}="CD Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="off"
+
+CTL{reset}="mixer"
+CTL{name}="Mono Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="$env{pvolume}",RESULT!="0",CTL{values}="$env{ppercent}"
+CTL{name}="Mono Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Mono Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="$env{pvolume}",RESULT!="0",CTL{values}="$env{ppercent}"
+CTL{name}="Master Mono Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="AC97 Playback Volume",CTL{do_search}=="1", \
+  CTL{values}="100%"
+CTL{name}="AC97 Playback Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+#
+# Powermacs
+#
+
+CTL{reset}="mixer"
+CTL{name}="DRC Range",CTL{do_search}=="1", \
+  CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
+
+# **************************************************************************
+# capture
+# **************************************************************************
+
+CTL{reset}="mixer"
+CTL{name}="Capture Volume",CTL{do_search}=="1", \
+  CTL{write}!="$env{cvolume}",CTL{values}="$env{cpercent}"
+CTL{name}="Capture Switch",CTL{do_search}=="1", \
+  CTL{values}="on"
+
+CTL{name}="Capture Source",PROGRAM!="__ctl_search", GOTO=""
+CTL{enums}=="*|Internal Mic|*",CTL{values}="Internal Mic", GOTO=""
+CTL{enums}=="*|Mic|*",CTL{values}="Mic"
+LABEL=""
+
+CTL{name}="Input Source",PROGRAM!="__ctl_search", GOTO=""
+CTL{enums}=="*|Internal Mic|*",CTL{values}="Internal Mic", GOTO=""
+CTL{enums}=="*|Mic|*",CTL{values}="Mic"
+LABEL=""
+
+CTL{name}="Digital Input Source",PROGRAM!="__ctl_search", GOTO=""
+CTL{enums}=="*|Digital Mic 1|*",CTL{values}="Digital Mic 1", GOTO=""
+CTL{enums}=="*|Mic|*",CTL{values}="Mic"
+LABEL=""
+
+CTL{name}="Mic Boost",CTL{do_search}=="1", CTL{values}="on"
+CTL{name}="Internal Mic Boost",CTL{do_search}=="1", CTL{values}="on"
diff --git a/resources/alsa/init/hda b/resources/alsa/init/hda
new file mode 100644
index 0000000000000000000000000000000000000000..7581095893f8f07836dc450fd752343cbf36c84d
--- /dev/null
+++ b/resources/alsa/init/hda
@@ -0,0 +1,39 @@
+# Configuration for HDA Intel driver (High Definition Audio - Azalia)
+
+CARDINFO{mixername}=="Realtek ALC880", \
+  ATTR{subsystem_vendor}=="0x1025", ATTR{subsystem_device}=="0x0070", \
+  GOTO="Acer Travelmate 8100"
+CARDINFO{mixername}=="Analog Devices AD1984", \
+  ATTR{subsystem_vendor}=="0x17aa", ATTR{subsystem_device}=="0x20ac", \
+  GOTO="Lenovo T61"
+RESULT="false", EXIT="return"
+ 
+LABEL="Acer Travelmate 8100"
+# playback
+CTL{reset}="mixer"
+CTL{name}="Master Playback Volume", CTL{values}="-21dB"
+CTL{name}="Master Playback Switch", CTL{values}="on"
+CTL{name}="Headphone Playback Switch", CTL{values}="on"
+CTL{name}="Front Playback Volume", CTL{values}="-29dB"
+CTL{name}="Front Playback Switch", CTL{values}="on"
+CTL{name}="PCM Playback Volume", CTL{values}="0dB"
+# capture
+CTL{name}="Input Source", CTL{value}="Mic"
+CTL{name}="Capture Volume", CTL{values}="20dB"
+CTL{name}="Capture Switch", CTL{values}="on"
+RESULT="true", EXIT="return"
+
+LABEL="Lenovo T61"
+# playback
+CTL{reset}="mixer"
+CTL{name}="Master Playback Volume", CTL{values}="-13.5dB"
+CTL{name}="Master Playback Switch", CTL{values}="on"
+CTL{name}="Headphone Playback Switch", CTL{values}="on"
+CTL{name}="Speaker Playback Switch", CTL{values}="on"
+CTL{name}="PCM Playback Volume", CTL{values}="0dB"
+# capture
+CTL{name}="Input Source", CTL{value}="Internal Mic"
+CTL{name}="Internal Mic Boost", CTL{values}="1"
+CTL{name}="Capture Volume", CTL{values}="9dB"
+CTL{name}="Capture Switch", CTL{values}="on"
+RESULT="true", EXIT="return"
diff --git a/resources/alsa/init/help b/resources/alsa/init/help
new file mode 100644
index 0000000000000000000000000000000000000000..4f0ba70b75ea8d587f5d7d9a559fbc41330c7a3f
--- /dev/null
+++ b/resources/alsa/init/help
@@ -0,0 +1,8 @@
+# help page
+
+PRINT="Available commands (identified by the environment variable CMD):\n\n"
+PRINT="  (not set)     Do a soundcard initialization\n"
+PRINT="  default       Do a default (guess method) initialization\n"
+PRINT="  help          Show this information\n"
+PRINT="  info          Print all available hardware identification\n"
+PRINT="  test          Do alsactl utility parser tests\n"
diff --git a/resources/alsa/init/info b/resources/alsa/init/info
new file mode 100644
index 0000000000000000000000000000000000000000..a4fea19c6868d88f3dc1fe034b925db5e6876084
--- /dev/null
+++ b/resources/alsa/init/info
@@ -0,0 +1,22 @@
+# show information about card
+
+PRINT="CARDINFO:\n"
+PRINT="  CARDINFO{id}=\"$CARDINFO{id}\"\n"
+PRINT="  CARDINFO{card}=\"$CARDINFO{card}\"\n"
+PRINT="  CARDINFO{driver}=\"$CARDINFO{driver}\"\n"
+PRINT="  CARDINFO{name}=\"$CARDINFO{name}\"\n"
+PRINT="  CARDINFO{longname}=\"$CARDINFO{longname}\"\n"
+PRINT="  CARDINFO{mixername}=\"$CARDINFO{mixername}\"\n"
+PRINT="  CARDINFO{components}=\"$CARDINFO{components}\"\n"
+
+# sysfs stuff
+PRINT="sysfs:\n"
+ATTR{bus}=="*", PRINT="  ATTR{bus}=\"$ATTR{bus}\"\n"
+ATTR{class}=="*", PRINT="  ATTR{class}=\"$ATTR{class}\"\n"
+ATTR{driver}=="*", PRINT="  ATTR{driver}=\"$ATTR{driver}\"\n"
+ATTR{vendor}=="*", PRINT="  ATTR{vendor}=\"$ATTR{vendor}\"\n"
+ATTR{device}=="*", PRINT="  ATTR{device}=\"$ATTR{device}\"\n"
+ATTR{subsystem_vendor}=="*", \
+  PRINT="  ATTR{subsystem_vendor}=\"$ATTR{subsystem_vendor}\"\n"
+ATTR{subsystem_device}=="*", \
+  PRINT="  ATTR{subsystem_device}=\"$ATTR{subsystem_device}\"\n"
diff --git a/resources/alsa/init/test b/resources/alsa/init/test
new file mode 100644
index 0000000000000000000000000000000000000000..56659f8e3376c0b35f24b599b5ea023fd7d60994
--- /dev/null
+++ b/resources/alsa/init/test
@@ -0,0 +1,270 @@
+# Test code
+# Just for debugging purposes
+
+PRINT="Default CTL:\n"
+PRINT="  CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="  CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="  CTL{device}=\"$ctl{device}\"\n"
+PRINT="  CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="  CTL{name}=\"$ctl{name}\"\n"
+PRINT="  CTL{index}=\"$ctl{index}\"\n"
+
+CTL{reset}="mixer"
+
+PRINT="After CTL{reset}=\"mixer\":\n"
+PRINT="  CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="  CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="  CTL{device}=\"$ctl{device}\"\n"
+PRINT="  CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="  CTL{name}=\"$ctl{name}\"\n"
+PRINT="  CTL{index}=\"$ctl{index}\"\n"
+
+CTL{numid}="987"
+CTL{iface}="sequencer"
+CTL{device}="10"
+CTL{subdevice}="20"
+CTL{name}="Just Test"
+CTL{index}="999"
+
+PRINT="After test sequence:\n"
+PRINT="  CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="  CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="  CTL{device}=\"$ctl{device}\"\n"
+PRINT="  CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="  CTL{name}=\"$ctl{name}\"\n"
+PRINT="  CTL{index}=\"$ctl{index}\"\n"
+
+ERROR="Ignore following error:\n  "
+PROGRAM="__just_test"
+
+PRINT="CTL{do_count} test:\n"
+CTL{search}="mixer", CTL{name}="*Switch*", \
+  PRINT="  *Switch* count result: $ctl{do_count}\n"
+
+PRINT="__ctl_search test:\n"
+CTL{search}="mixer", CTL{name}="*Switch*", PROGRAM!="__ctl_search", GOTO="skip_switch_search"
+PRINT="  *Switch 0* search result: $result\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+CTL{search}="mixer", CTL{name}="*Switch*", PROGRAM!="__ctl_search 1", GOTO="skip_switch_search"
+PRINT="  *Switch 1* search result: $result\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+
+PRINT="First ten elements:\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 0}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #0:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 1}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #1:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 2}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #2:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 3}!="3", GOTO="skip_first_ten_search"
+PRINT="  Element #3:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 4}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #4:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 5}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #5:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 6}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #6:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 7}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #7:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 8}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #8:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+CTL{search}="mixer", CTL{name}="*", CTL{do_search 9}!="1", GOTO="skip_first_ten_search"
+PRINT="  Element #9:\n"
+PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
+PRINT="    CTL{iface}=\"$ctl{iface}\"\n"
+PRINT="    CTL{device}=\"$ctl{device}\"\n"
+PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
+PRINT="    CTL{name}=\"$ctl{name}\"\n"
+PRINT="    CTL{index}=\"$ctl{index}\"\n"
+PRINT="    CTL{type}=\"$ctl{type}\"\n"
+PRINT="    CTL{attr}=\"$ctl{attr}\"\n"
+PRINT="    CTL{owner}=\"$ctl{owner}\"\n"
+PRINT="    CTL{count}=\"$ctl{count}\"\n"
+PRINT="    CTL{min}=\"$ctl{min}\"\n"
+PRINT="    CTL{max}=\"$ctl{max}\"\n"
+PRINT="    CTL{step}=\"$ctl{step}\"\n"
+PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
+PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
+PRINT="    CTL{items}=\"$ctl{items}\"\n"
+PRINT="    CTL{value}=\"$ctl{value}\"\n"
+LABEL="skip_first_ten_search"
+
+PRINT="Elements write test #1:\n", \
+  CTL{search}="mixer", CTL{name}="Front Playback Switch", \
+  CTL{do_search}=="1", CTL{value}="on,on", \
+  PRINT="  result=$result\n"
+PRINT="Elements write test #2:\n", \
+  CTL{search}="mixer", CTL{name}="Front Playback Volume", \
+  CTL{do_search}=="1", CTL{value}="32,32", \
+  PRINT="  result=$result\n"
+PRINT="Elements write test #3:\n", \
+  CTL{search}="mixer", CTL{name}="Front Playback Volume Error", \
+  CTL{do_search}=="1", \
+PRINT="  result=$result\n"
+
+#CTL{reset}="mixer", CTL{name}="Input Source", PRINT="***$ctl{enums}\n"
+
+PRINT="\nAll tests done..\n"
diff --git a/resources/alsa/pcm/center_lfe.conf b/resources/alsa/pcm/center_lfe.conf
new file mode 100644
index 0000000000000000000000000000000000000000..4ef6f49768b25cf7ecca14de7e0b55f01aab363e
--- /dev/null
+++ b/resources/alsa/pcm/center_lfe.conf
@@ -0,0 +1,58 @@
+#
+#  Hardware output from center & lfe speakers
+#
+
+pcm.!center_lfe {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_CENTER_LFE_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.center_lfe.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_CENTER_LFE_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.center_lfe.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.center_lfe." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "Center and Subwoofer speakers"
+		device $DEV
+	}
+}
diff --git a/resources/alsa/pcm/default.conf b/resources/alsa/pcm/default.conf
new file mode 100644
index 0000000000000000000000000000000000000000..864a90339f152e9c33cadafd026a1fe71b8a0bb3
--- /dev/null
+++ b/resources/alsa/pcm/default.conf
@@ -0,0 +1,57 @@
+#
+# Default output
+#
+
+pcm.!default {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.card
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		# use card-specific definition if exists
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.default:CARD=" $CARD
+			]
+		}
+		default {
+			# use plughw as default
+			type plug
+			slave.pcm {
+				type hw
+				card $CARD
+			}
+			hint.device 0
+		}
+	}
+	hint {
+		description "Default Audio Device"
+		device_output {
+			@func refer
+			name defaults.pcm.dmix.device
+		}
+		device_input {
+			@func refer
+			name defaults.pcm.dsnoop.device
+		}
+	}
+}
diff --git a/resources/alsa/pcm/dmix.conf b/resources/alsa/pcm/dmix.conf
new file mode 100644
index 0000000000000000000000000000000000000000..50e573da5d35acb05cfc41addaf0079f2535d1fd
--- /dev/null
+++ b/resources/alsa/pcm/dmix.conf
@@ -0,0 +1,127 @@
+#
+# dmix output
+#
+
+pcm.!dmix {
+	@args [ CARD DEV SUBDEV FORMAT RATE CHANNELS ]
+	@args.CARD {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.dmix.card
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.dmix.device
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default 0
+	}
+	@args.FORMAT {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.dmix.format
+		}
+	}
+	@args.RATE {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.dmix.rate
+		}
+	}
+	@args.CHANNELS {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.dmix.channels
+		}
+	}
+	type dmix
+	ipc_key {
+		@func refer
+		name defaults.pcm.ipc_key
+	}
+	ipc_gid {
+		@func refer
+		name defaults.pcm.ipc_gid
+	}
+	ipc_perm {
+		@func refer
+		name defaults.pcm.ipc_perm
+	}
+	tstamp_type {
+		@func refer
+		name defaults.pcm.tstamp_type
+	}
+	slave {
+		pcm {
+			type hw
+			card $CARD
+			device $DEV
+			subdevice $SUBDEV
+		}
+		format $FORMAT
+		rate $RATE
+		channels $CHANNELS
+		period_size {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"defaults.dmix."
+					{
+						@func card_driver
+						card $CARD
+					}
+					".period_size"
+				]
+			}
+			default 1024
+		}		
+		period_time {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"defaults.dmix."
+					{
+						@func card_driver
+						card $CARD
+					}
+					".period_time"
+				]
+			}
+			default -1
+		}		
+		periods {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"defaults.dmix."
+					{
+						@func card_driver
+						card $CARD
+					}
+					".periods"
+				]
+			}
+			default 16
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.extended
+		}
+		description "Direct sample mixing device"
+		device_output $DEV
+	}
+}
diff --git a/resources/alsa/pcm/dpl.conf b/resources/alsa/pcm/dpl.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1009bb384d58608129eb078f6df218026c5c8cc9
--- /dev/null
+++ b/resources/alsa/pcm/dpl.conf
@@ -0,0 +1,43 @@
+pcm.!dpl {
+	@args [ SLAVE ]
+	@args.SLAVE {
+		type string
+	}
+	type route
+	slave.pcm $SLAVE
+	slave.channels 2
+	# input: FL/FR/SL/SR/C/LFE
+	# S=SL+SR, LFE not used
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.0 0.707
+	ttable.2.1 -0.707
+	ttable.3.0 0.707
+	ttable.3.1 -0.707
+	ttable.4.0 0.707
+	ttable.4.1 0.707
+	ttable.5.0 0
+	ttable.5.1 0
+}
+
+pcm.!dpl2 {
+	@args [SLAVE]
+	@args.SLAVE {
+		type string
+	}
+	type route
+	slave.pcm $SLAVE
+	slave.channels 2
+	# input: FL/FR/SL/SR/C/LFE
+	# LFE not used
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.0 0.866
+	ttable.2.1 -0.5
+	ttable.3.0 0.5
+	ttable.3.1 -0.866
+	ttable.4.0 0.707
+	ttable.4.1 0.707
+	ttable.5.0 0
+	ttable.5.1 0
+}
diff --git a/resources/alsa/pcm/dsnoop.conf b/resources/alsa/pcm/dsnoop.conf
new file mode 100644
index 0000000000000000000000000000000000000000..f4336e5f5e070a071bba21f573f64fabdd4ff645
--- /dev/null
+++ b/resources/alsa/pcm/dsnoop.conf
@@ -0,0 +1,119 @@
+#
+# dsnoop
+#
+
+pcm.!dsnoop {
+	@args [ CARD DEV SUBDEV FORMAT RATE ]
+	@args.CARD {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.dsnoop.card
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.dsnoop.device
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default 0
+	}
+	@args.FORMAT {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.dmix.format
+		}
+	}
+	@args.RATE {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.dmix.rate
+		}
+	}
+	type dsnoop
+	ipc_key {
+		@func refer
+		name defaults.pcm.ipc_key
+	}	
+	ipc_gid {
+		@func refer
+		name defaults.pcm.ipc_gid
+	}
+	ipc_perm {
+		@func refer
+		name defaults.pcm.ipc_perm
+	}
+	tstamp_type {
+		@func refer
+		name defaults.pcm.tstamp_type
+	}
+	slave {
+		pcm {
+			type hw
+			card $CARD
+			device $DEV
+			subdevice $SUBDEV
+		}
+		format $FORMAT
+		rate $RATE
+		period_size {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"cards."
+					{
+						@func card_driver
+						card $CARD
+					}
+					".pcm.dsnoop.period_size"
+				]
+			}
+			default 1024
+		}		
+		period_time {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"cards."
+					{
+						@func card_driver
+						card $CARD
+					}
+					".pcm.dsnoop.period_time"
+				]
+			}
+			default -1
+		}		
+		periods {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"cards."
+					{
+						@func card_driver
+						card $CARD
+					}
+					".pcm.dsnoop.periods"
+				]
+			}
+			default 16
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.extended
+		}
+		description "Direct sample snooping device"
+		device_input $DEV
+	}
+}
diff --git a/resources/alsa/pcm/front.conf b/resources/alsa/pcm/front.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a5839b3d067d8bff097c18dcec1cddd73030eb31
--- /dev/null
+++ b/resources/alsa/pcm/front.conf
@@ -0,0 +1,60 @@
+#
+# Hardware output from front speakers
+#
+
+pcm.!front {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_FRONT_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.front.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_FRONT_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.front.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.front." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "Front output / input"
+		device_output $DEV
+		device_input $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/pcm/hdmi.conf b/resources/alsa/pcm/hdmi.conf
new file mode 100644
index 0000000000000000000000000000000000000000..aad7065c9f8721b19867598e22c97cee3da5d198
--- /dev/null
+++ b/resources/alsa/pcm/hdmi.conf
@@ -0,0 +1,83 @@
+#
+#  Hardware output from HDMI
+#
+
+pcm.!hdmi {
+	@args [ CARD DEV AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_IEC958_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.iec958.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_IEC958_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.iec958.device
+			}
+		}
+	}
+	@args.AES0 {
+		type integer
+		# consumer, not-copyright, emphasis-none, mode=0
+		default 0x04
+	}
+	@args.AES1 {
+		type integer
+		# original, PCM coder
+		default 0x82
+	}
+	@args.AES2 {
+		type integer
+		# source and channel
+		default 0x00
+	}
+	@args.AES3 {
+		type integer
+		# fs=48000Hz, clock accuracy=1000ppm
+		default 0x02
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.hdmi." $DEV ":"
+				"CARD=" $CARD ","
+				"AES0=" $AES0 ","
+				"AES1=" $AES1 ","
+				"AES2=" $AES2 ","
+				"AES3=" $AES3
+			]
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "HDMI Audio Output"
+		device $DEV
+	}
+}
diff --git a/resources/alsa/pcm/iec958.conf b/resources/alsa/pcm/iec958.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2b084d6fd1d75706830ee2813bd03de884b66e66
--- /dev/null
+++ b/resources/alsa/pcm/iec958.conf
@@ -0,0 +1,83 @@
+#
+#  Hardware output from iec958
+#
+
+pcm.!iec958 {
+	@args [ CARD DEV AES0 AES1 AES2 AES3 ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_IEC958_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.iec958.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_IEC958_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.iec958.device
+			}
+		}
+	}
+	@args.AES0 {
+		type integer
+		# consumer, not-copyright, emphasis-none, mode=0
+		default 0x04
+	}
+	@args.AES1 {
+		type integer
+		# original, PCM coder
+		default 0x82
+	}
+	@args.AES2 {
+		type integer
+		# source and channel
+		default 0x00
+	}
+	@args.AES3 {
+		type integer
+		# fs=48000Hz, clock accuracy=1000ppm
+		default 0x02
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.iec958." $DEV ":"
+				"CARD=" $CARD ","
+				"AES0=" $AES0 ","
+				"AES1=" $AES1 ","
+				"AES2=" $AES2 ","
+				"AES3=" $AES3
+			]
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "IEC958 (S/PDIF) Digital Audio Output"
+		device_output $DEV
+	}
+}
diff --git a/resources/alsa/pcm/modem.conf b/resources/alsa/pcm/modem.conf
new file mode 100644
index 0000000000000000000000000000000000000000..0af0e72c568a0ecacde72549e81fc2f7e21d2adb
--- /dev/null
+++ b/resources/alsa/pcm/modem.conf
@@ -0,0 +1,106 @@
+#
+# "raw" modem - phoneline
+#
+
+pcm.!phoneline {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_MODEM_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.modem.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_MODEM_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.modem.device
+			}
+		}
+	}
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards."
+			{
+				@func card_driver
+				card $CARD
+			}
+			".pcm.modem." $DEV ":CARD=" $CARD
+		]
+	}
+	hint.show off
+}
+
+#
+#  "autohooked" modem
+#
+
+pcm.!modem {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_MODEM_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.modem.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_MODEM_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.modem.device
+			}
+		}
+	}
+	type hooks
+	slave {
+		pcm {
+			@func concat
+			strings [
+				"cards.pcm.phoneline:CARD=" $CARD ",DEV=" $DEV
+			]
+		}
+	}
+	hooks.0 {
+		type ctl_elems
+		hook_args [
+		{
+			name "Off-hook Switch"
+			preserve true
+			value "on"
+			lock false
+			optional true
+		}
+		]
+	}
+	hint.show off
+}
diff --git a/resources/alsa/pcm/rear.conf b/resources/alsa/pcm/rear.conf
new file mode 100644
index 0000000000000000000000000000000000000000..85c70aab180fe911203873a5da640a4406ca4105
--- /dev/null
+++ b/resources/alsa/pcm/rear.conf
@@ -0,0 +1,58 @@
+#
+# Hardware output from rear speakers
+#
+
+pcm.!rear {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_REAR_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.rear.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_REAR_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.rear.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.rear." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "Rear speakers"
+		device $DEV
+	}
+}
diff --git a/resources/alsa/pcm/side.conf b/resources/alsa/pcm/side.conf
new file mode 100644
index 0000000000000000000000000000000000000000..4a81af09c8a684975501e6099522fad390810565
--- /dev/null
+++ b/resources/alsa/pcm/side.conf
@@ -0,0 +1,58 @@
+#
+# Hardware output from side speakers
+#
+
+pcm.!side {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SIDE_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.side.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SIDE_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.side.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.side." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "Side speakers"
+		device $DEV
+	}
+}
diff --git a/resources/alsa/pcm/surround21.conf b/resources/alsa/pcm/surround21.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ad19507bba58271adfac15d8d3baf154f791e5bf
--- /dev/null
+++ b/resources/alsa/pcm/surround21.conf
@@ -0,0 +1,62 @@
+#
+#  Hardware output from 2.1 speakers.
+#  Samples must be positioned:
+#    chn0 - front left
+#    chn1 - front right
+#    chn2 - LFE
+#
+
+pcm.!surround21 {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SURROUND21_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround21.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SURROUND21_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround21.device
+			}
+		}
+	}
+	type route
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.surround51." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	ttable.0.FL 1
+	ttable.1.FR 1
+	ttable.2.LFE 1
+	hint {
+		description "2.1 Surround output to Front and Subwoofer speakers"
+		device_output $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/pcm/surround40.conf b/resources/alsa/pcm/surround40.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7c615022f5006f9dae9ae066db0a613eb69e54eb
--- /dev/null
+++ b/resources/alsa/pcm/surround40.conf
@@ -0,0 +1,60 @@
+#
+#  Hardware output from 4.0 speakers.
+#  Samples must be positioned:
+#    chn0 - front left
+#    chn1 - front right
+#    chn2 - rear left
+#    chn3 - rear right
+#
+
+pcm.!surround40 {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SURROUND40_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround40.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SURROUND40_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround40.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.surround40." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		description "4.0 Surround output to Front and Rear speakers"
+		device_output $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/pcm/surround41.conf b/resources/alsa/pcm/surround41.conf
new file mode 100644
index 0000000000000000000000000000000000000000..cb6c0445ae07127781aba825f6437e4ada06fbdc
--- /dev/null
+++ b/resources/alsa/pcm/surround41.conf
@@ -0,0 +1,66 @@
+#
+#  Hardware output from 4.1 speakers.
+#  Samples must be positioned:
+#    chn0 - front left
+#    chn1 - front right
+#    chn2 - rear left
+#    chn3 - rear right
+#    chn4 - LFE
+#
+
+pcm.!surround41 {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SURROUND41_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround41.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SURROUND41_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround41.device
+			}
+		}
+	}
+	type route
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.surround51." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	ttable.0.FL 1
+	ttable.1.FR 1
+	ttable.2.RL 1
+	ttable.3.RR 1
+	ttable.4.LFE 1
+	hint {
+		description "4.1 Surround output to Front, Rear and Subwoofer speakers"
+		device_output $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/pcm/surround50.conf b/resources/alsa/pcm/surround50.conf
new file mode 100644
index 0000000000000000000000000000000000000000..70d54069f8a3bd6cea149424b4e6c70cce01183d
--- /dev/null
+++ b/resources/alsa/pcm/surround50.conf
@@ -0,0 +1,66 @@
+#
+#  Hardware output from 5.0 speakers.
+#  Samples must be positioned:
+#    chn0 - front left
+#    chn1 - front right
+#    chn2 - rear left
+#    chn3 - rear right
+#    chn4 - center
+#
+
+pcm.!surround50 {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SURROUND50_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround50.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SURROUND50_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround50.device
+			}
+		}
+	}
+	type route
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.surround51." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	ttable.0.FL 1
+	ttable.1.FR 1
+	ttable.2.RL 1
+	ttable.3.RR 1
+	ttable.4.FC 1
+	hint {
+		description "5.0 Surround output to Front, Center and Rear speakers"
+		device_output $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/pcm/surround51.conf b/resources/alsa/pcm/surround51.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d0236e42d3329c387cbb2f5972c18f191fea2bd7
--- /dev/null
+++ b/resources/alsa/pcm/surround51.conf
@@ -0,0 +1,62 @@
+#
+#  Hardware output from 5.1 speakers
+#  Samples must be positioned:
+#    chn0 - front left
+#    chn1 - front right
+#    chn2 - rear left
+#    chn3 - rear right
+#    chn4 - center
+#    chn5 - lfe
+#
+
+pcm.!surround51 {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SURROUND51_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround51.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SURROUND51_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround51.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.surround51." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		description "5.1 Surround output to Front, Center, Rear and Subwoofer speakers"
+		device_output $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/pcm/surround71.conf b/resources/alsa/pcm/surround71.conf
new file mode 100644
index 0000000000000000000000000000000000000000..66792ddebbc030d38bd5eb218580dd1d2d7960f4
--- /dev/null
+++ b/resources/alsa/pcm/surround71.conf
@@ -0,0 +1,64 @@
+#
+#  Hardware output from 7.1 speakers
+#  Samples must be positioned:
+#    chn0 - front left
+#    chn1 - front right
+#    chn2 - rear left
+#    chn3 - rear right
+#    chn4 - center
+#    chn5 - lfe
+#    chn6 - side left
+#    chn7 - side right
+#
+
+pcm.!surround71 {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_SURROUND71_CARD
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround71.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_SURROUND71_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.surround71.device
+			}
+		}
+	}
+	type empty
+	slave.pcm {
+		@func refer
+		name {
+			@func concat
+			strings [
+				"cards."
+				{
+					@func card_driver
+					card $CARD
+				}
+				".pcm.surround71." $DEV ":CARD=" $CARD
+			]
+		}
+	}
+	hint {
+		description "7.1 Surround output to Front, Center, Side, Rear and Woofer speakers"
+		device_output $DEV
+		omit_noargs true
+	}
+}
diff --git a/resources/alsa/speaker-test/sample_map.csv b/resources/alsa/speaker-test/sample_map.csv
new file mode 100644
index 0000000000000000000000000000000000000000..20d8ed2f1b04fc43a5c3f06eeaf82d02c50e69c4
--- /dev/null
+++ b/resources/alsa/speaker-test/sample_map.csv
@@ -0,0 +1,2 @@
+0, "Front Left", "/usr/share/alsa/samples/Front_Left.wav"
+1, "Front Right", "/usr/share/alsa/samples/Front_Right.wav"
diff --git a/resources/armv7l/bin/curl b/resources/armv7l/bin/curl
new file mode 100755
index 0000000000000000000000000000000000000000..53a213b13623a1c71d49683b1854043e5330897e
Binary files /dev/null and b/resources/armv7l/bin/curl differ
diff --git a/resources/armv7l/bin/cyclictest b/resources/armv7l/bin/cyclictest
new file mode 100755
index 0000000000000000000000000000000000000000..25279296934adff1ca4c92e877394b66c95f38d8
Binary files /dev/null and b/resources/armv7l/bin/cyclictest differ
diff --git a/resources/armv7l/lib/libcurl.so b/resources/armv7l/lib/libcurl.so
new file mode 120000
index 0000000000000000000000000000000000000000..373a73af27acef3429d62737f49156b80f774118
--- /dev/null
+++ b/resources/armv7l/lib/libcurl.so
@@ -0,0 +1 @@
+libcurl.so.4.4.0
\ No newline at end of file
diff --git a/resources/armv7l/lib/libcurl.so.4 b/resources/armv7l/lib/libcurl.so.4
new file mode 120000
index 0000000000000000000000000000000000000000..373a73af27acef3429d62737f49156b80f774118
--- /dev/null
+++ b/resources/armv7l/lib/libcurl.so.4
@@ -0,0 +1 @@
+libcurl.so.4.4.0
\ No newline at end of file
diff --git a/resources/armv7l/lib/libcurl.so.4.4.0 b/resources/armv7l/lib/libcurl.so.4.4.0
new file mode 100755
index 0000000000000000000000000000000000000000..61946fafde66cdc550a0cc37aa670e5a52d6ee77
Binary files /dev/null and b/resources/armv7l/lib/libcurl.so.4.4.0 differ
diff --git a/resources/armv7l/lib/libfaad.so b/resources/armv7l/lib/libfaad.so
new file mode 120000
index 0000000000000000000000000000000000000000..a95c965b223aa45f07d01094c1aa5390e6f25d0e
--- /dev/null
+++ b/resources/armv7l/lib/libfaad.so
@@ -0,0 +1 @@
+libfaad.so.2.0.0
\ No newline at end of file
diff --git a/resources/armv7l/lib/libfaad.so.2 b/resources/armv7l/lib/libfaad.so.2
new file mode 120000
index 0000000000000000000000000000000000000000..a95c965b223aa45f07d01094c1aa5390e6f25d0e
--- /dev/null
+++ b/resources/armv7l/lib/libfaad.so.2
@@ -0,0 +1 @@
+libfaad.so.2.0.0
\ No newline at end of file
diff --git a/resources/armv7l/lib/libfaad.so.2.0.0 b/resources/armv7l/lib/libfaad.so.2.0.0
new file mode 100755
index 0000000000000000000000000000000000000000..68aa96d0b41ca0bc540bb2d958d470f1ce7856c1
Binary files /dev/null and b/resources/armv7l/lib/libfaad.so.2.0.0 differ
diff --git a/resources/armv7l/lib/libmpg123.so b/resources/armv7l/lib/libmpg123.so
new file mode 120000
index 0000000000000000000000000000000000000000..ead69b0f96fd3297a3f1a39c590fcff0168ab3ef
--- /dev/null
+++ b/resources/armv7l/lib/libmpg123.so
@@ -0,0 +1 @@
+libmpg123.so.0.43.0
\ No newline at end of file
diff --git a/resources/armv7l/lib/libmpg123.so.0 b/resources/armv7l/lib/libmpg123.so.0
new file mode 120000
index 0000000000000000000000000000000000000000..ead69b0f96fd3297a3f1a39c590fcff0168ab3ef
--- /dev/null
+++ b/resources/armv7l/lib/libmpg123.so.0
@@ -0,0 +1 @@
+libmpg123.so.0.43.0
\ No newline at end of file
diff --git a/resources/armv7l/lib/libmpg123.so.0.43.0 b/resources/armv7l/lib/libmpg123.so.0.43.0
new file mode 100755
index 0000000000000000000000000000000000000000..1ca0858b5b8b470a30b089ec8834b053ef9f4b13
Binary files /dev/null and b/resources/armv7l/lib/libmpg123.so.0.43.0 differ
diff --git a/resources/armv7l/lib/libvorbisenc.so b/resources/armv7l/lib/libvorbisenc.so
new file mode 120000
index 0000000000000000000000000000000000000000..ab1e5859ac07db738cc01d6e502c28e62ad5bbc0
--- /dev/null
+++ b/resources/armv7l/lib/libvorbisenc.so
@@ -0,0 +1 @@
+libvorbisenc.so.2.0.11
\ No newline at end of file
diff --git a/resources/armv7l/lib/libvorbisenc.so.2 b/resources/armv7l/lib/libvorbisenc.so.2
new file mode 120000
index 0000000000000000000000000000000000000000..ab1e5859ac07db738cc01d6e502c28e62ad5bbc0
--- /dev/null
+++ b/resources/armv7l/lib/libvorbisenc.so.2
@@ -0,0 +1 @@
+libvorbisenc.so.2.0.11
\ No newline at end of file
diff --git a/resources/armv7l/lib/libvorbisenc.so.2.0.11 b/resources/armv7l/lib/libvorbisenc.so.2.0.11
new file mode 100755
index 0000000000000000000000000000000000000000..2ef83b4518ea6d66f6beaac25be41912769b5ba1
Binary files /dev/null and b/resources/armv7l/lib/libvorbisenc.so.2.0.11 differ
diff --git a/resources/grub.template b/resources/grub.template
new file mode 100644
index 0000000000000000000000000000000000000000..2077d4ef88049bfc3ebffc287e40c7746e2afc23
--- /dev/null
+++ b/resources/grub.template
@@ -0,0 +1,36 @@
+# If you change this file, run 'update-grub' afterwards to update
+# /boot/grub/grub.cfg.
+# For full documentation of the options in this file, see:
+# info -f grub -n 'Simple configuration'
+
+#GRUB_DEFAULT=0
+GRUB_DEFAULT="1>Ubuntu, with Linux @NEW_VERSION@"
+#GRUB_HIDDEN_TIMEOUT=0
+GRUB_HIDDEN_TIMEOUT_QUIET=true
+GRUB_TIMEOUT=3
+GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
+GRUB_CMDLINE_LINUX_DEFAULT="text 3 biosdevname=0 net.ifnames=0 clocksource=@NEW_CLOCKSOURCE@ @NEW_OPTIONS@"
+GRUB_CMDLINE_LINUX=""
+
+# Uncomment to enable BadRAM filtering, modify to suit your needs
+# This works with Linux (no patch required) and with any kernel that obtains
+# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
+GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
+
+# Uncomment to disable graphical terminal (grub-pc only)
+GRUB_TERMINAL=console
+
+# The resolution used on graphical terminal
+# note that you can use only modes which your graphic card supports via VBE
+# you can see them in real GRUB with the command `vbeinfo'
+#GRUB_GFXMODE=640x480
+
+# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
+#GRUB_DISABLE_LINUX_UUID=true
+
+# Uncomment to disable generation of recovery mode menu entries
+#GRUB_DISABLE_RECOVERY="true"
+
+# Uncomment to get a beep at grub start
+GRUB_INIT_TUNE="480 440 1"
+
diff --git a/resources/i686/bin/curl b/resources/i686/bin/curl
new file mode 100755
index 0000000000000000000000000000000000000000..a3a96c855f0b40cf9c3f4b3d4f6c46746665fcb6
Binary files /dev/null and b/resources/i686/bin/curl differ
diff --git a/resources/i686/bin/cyclictest b/resources/i686/bin/cyclictest
new file mode 100755
index 0000000000000000000000000000000000000000..f6f25a93412a4ea3ae015570607f8fc58e8c7a6d
Binary files /dev/null and b/resources/i686/bin/cyclictest differ
diff --git a/resources/i686/bin/uhubctl b/resources/i686/bin/uhubctl
new file mode 100755
index 0000000000000000000000000000000000000000..cdef301543a1a584f4ecd56e409f5faba1fb7d25
Binary files /dev/null and b/resources/i686/bin/uhubctl differ
diff --git a/resources/i686/lib/libcurl.so b/resources/i686/lib/libcurl.so
new file mode 120000
index 0000000000000000000000000000000000000000..373a73af27acef3429d62737f49156b80f774118
--- /dev/null
+++ b/resources/i686/lib/libcurl.so
@@ -0,0 +1 @@
+libcurl.so.4.4.0
\ No newline at end of file
diff --git a/resources/i686/lib/libcurl.so.4 b/resources/i686/lib/libcurl.so.4
new file mode 120000
index 0000000000000000000000000000000000000000..373a73af27acef3429d62737f49156b80f774118
--- /dev/null
+++ b/resources/i686/lib/libcurl.so.4
@@ -0,0 +1 @@
+libcurl.so.4.4.0
\ No newline at end of file
diff --git a/resources/i686/lib/libcurl.so.4.4.0 b/resources/i686/lib/libcurl.so.4.4.0
new file mode 100755
index 0000000000000000000000000000000000000000..99598d4dbd0e07a62c0d51bb777170bcfe2bb67e
Binary files /dev/null and b/resources/i686/lib/libcurl.so.4.4.0 differ
diff --git a/resources/i686/lib/libixml.so b/resources/i686/lib/libixml.so
new file mode 120000
index 0000000000000000000000000000000000000000..0916b285f93853209b81565c84100fdd79b7300b
--- /dev/null
+++ b/resources/i686/lib/libixml.so
@@ -0,0 +1 @@
+/usr/local/libixml.so.2.0.8
\ No newline at end of file
diff --git a/resources/i686/lib/libixml.so.2 b/resources/i686/lib/libixml.so.2
new file mode 120000
index 0000000000000000000000000000000000000000..0916b285f93853209b81565c84100fdd79b7300b
--- /dev/null
+++ b/resources/i686/lib/libixml.so.2
@@ -0,0 +1 @@
+/usr/local/libixml.so.2.0.8
\ No newline at end of file
diff --git a/resources/i686/lib/libixml.so.2.0.8 b/resources/i686/lib/libixml.so.2.0.8
new file mode 100644
index 0000000000000000000000000000000000000000..23d95edd35963d8cc66c626ba93c07706f93ca6b
Binary files /dev/null and b/resources/i686/lib/libixml.so.2.0.8 differ
diff --git a/resources/i686/lib/libmpdclient.so b/resources/i686/lib/libmpdclient.so
new file mode 120000
index 0000000000000000000000000000000000000000..2ffb5d28e68dc92db36aa0fd7a50d005d7bdd189
--- /dev/null
+++ b/resources/i686/lib/libmpdclient.so
@@ -0,0 +1 @@
+/usr/local/lib/libmpdclient.so
\ No newline at end of file
diff --git a/resources/i686/lib/libmpdclient.so.2 b/resources/i686/lib/libmpdclient.so.2
new file mode 120000
index 0000000000000000000000000000000000000000..556f69cac04f6bf8efae6205a516366f1df41035
--- /dev/null
+++ b/resources/i686/lib/libmpdclient.so.2
@@ -0,0 +1 @@
+/usr/local/lib/libmpdclient.so.2.14
\ No newline at end of file
diff --git a/resources/i686/lib/libmpdclient.so.2.14 b/resources/i686/lib/libmpdclient.so.2.14
new file mode 100644
index 0000000000000000000000000000000000000000..5f7b4e57e71fff4fb6f8377d13dd2ae0b1c6beb0
Binary files /dev/null and b/resources/i686/lib/libmpdclient.so.2.14 differ
diff --git a/resources/i686/lib/libstdc++.so.6 b/resources/i686/lib/libstdc++.so.6
new file mode 120000
index 0000000000000000000000000000000000000000..470f7733336c7a57350d085750b61b9032b1b94f
--- /dev/null
+++ b/resources/i686/lib/libstdc++.so.6
@@ -0,0 +1 @@
+libstdc++.so.6.0.25
\ No newline at end of file
diff --git a/resources/i686/lib/libstdc++.so.6.0.25 b/resources/i686/lib/libstdc++.so.6.0.25
new file mode 100644
index 0000000000000000000000000000000000000000..e5b423ee3c33ca2cc39139c83baa65184dea5e49
Binary files /dev/null and b/resources/i686/lib/libstdc++.so.6.0.25 differ
diff --git a/resources/i686/lib/libthreadutil.so b/resources/i686/lib/libthreadutil.so
new file mode 120000
index 0000000000000000000000000000000000000000..491c95c878b86af31bb64a754f24d968ba7185ad
--- /dev/null
+++ b/resources/i686/lib/libthreadutil.so
@@ -0,0 +1 @@
+/usr/local/libthreadutil.so.6.0.4
\ No newline at end of file
diff --git a/resources/i686/lib/libthreadutil.so.6 b/resources/i686/lib/libthreadutil.so.6
new file mode 120000
index 0000000000000000000000000000000000000000..491c95c878b86af31bb64a754f24d968ba7185ad
--- /dev/null
+++ b/resources/i686/lib/libthreadutil.so.6
@@ -0,0 +1 @@
+/usr/local/libthreadutil.so.6.0.4
\ No newline at end of file
diff --git a/resources/i686/lib/libthreadutil.so.6.0.4 b/resources/i686/lib/libthreadutil.so.6.0.4
new file mode 100644
index 0000000000000000000000000000000000000000..6b1138d6e0e5bb91d970656364a84ff487832c64
Binary files /dev/null and b/resources/i686/lib/libthreadutil.so.6.0.4 differ
diff --git a/resources/i686/lib/libupnp.so.6 b/resources/i686/lib/libupnp.so.6
new file mode 120000
index 0000000000000000000000000000000000000000..57f6fee611eb7cff67fe497d04b8884636d90839
--- /dev/null
+++ b/resources/i686/lib/libupnp.so.6
@@ -0,0 +1 @@
+/usr/local/lib/libupnp.so.6.3.3
\ No newline at end of file
diff --git a/resources/i686/lib/libupnp.so.6.3 b/resources/i686/lib/libupnp.so.6.3
new file mode 120000
index 0000000000000000000000000000000000000000..57f6fee611eb7cff67fe497d04b8884636d90839
--- /dev/null
+++ b/resources/i686/lib/libupnp.so.6.3
@@ -0,0 +1 @@
+/usr/local/lib/libupnp.so.6.3.3
\ No newline at end of file
diff --git a/resources/i686/lib/libupnp.so.6.3.3 b/resources/i686/lib/libupnp.so.6.3.3
new file mode 100644
index 0000000000000000000000000000000000000000..52fb5e5cfb09545e7713b181f2d15cc73a0eb1cf
Binary files /dev/null and b/resources/i686/lib/libupnp.so.6.3.3 differ
diff --git a/resources/kernels/i686/bzImage b/resources/kernels/i686/bzImage
new file mode 100644
index 0000000000000000000000000000000000000000..609192af8b8c3f8ca9de13d90d197c057ee351da
Binary files /dev/null and b/resources/kernels/i686/bzImage differ
diff --git a/resources/kernels/i686/initrd.img b/resources/kernels/i686/initrd.img
new file mode 100644
index 0000000000000000000000000000000000000000..a5c879762563fb6b103902b2513417a209cd0c75
Binary files /dev/null and b/resources/kernels/i686/initrd.img differ
diff --git a/resources/kernels/x86_64/bzImage b/resources/kernels/x86_64/bzImage
new file mode 100644
index 0000000000000000000000000000000000000000..0664396db31b70ed04e4ace7ebf69b0d455fe6fc
Binary files /dev/null and b/resources/kernels/x86_64/bzImage differ
diff --git a/resources/kernels/x86_64/initrd.img b/resources/kernels/x86_64/initrd.img
new file mode 100644
index 0000000000000000000000000000000000000000..b906273f748649e5b3483cf5f3ce8c1c676d5aeb
Binary files /dev/null and b/resources/kernels/x86_64/initrd.img differ
diff --git a/resources/mympd.conf b/resources/mympd.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2c3c72595bee716be21853d88514b876933f1859
--- /dev/null
+++ b/resources/mympd.conf
@@ -0,0 +1,82 @@
+# myMPD configuration file
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+# myMPD (c) 2018-2021 Juergen Mang <mail@jcgames.de>
+# https://github.com/jcorporation/mympd
+#
+
+[mpd]
+#Connection to mpd, unix socket or host/port, socket preferred
+#host = /run/mpd/socket
+host = 127.0.0.1
+port = 6600
+#pass =
+#host = /run/mpd/socket
+
+#absolut path of music_directory of mpd
+#none = no local music_directory
+#auto = get music_directory from mpd (only supported, if connected to mpd socket)
+musicdirectory = /media/music
+
+#absolut path of mpd playlist_directory
+playlistdirectory = /media/playlists
+
+#MPD compiled with regex support
+regex = true
+
+
+[webserver]
+#Webserver options
+httphost = 0.0.0.0
+
+httpport = 8080
+
+#Enable ssl
+#Certificates are generated under /var/lib/mympd/ssl/
+#ssl = false
+#sslport = 443
+
+#Publishes some mpd and myMPD directories
+publish = false
+
+[mympd]
+Loglevel
+#0 = emerg
+#1 = alert
+#2 = crit
+#3 = error
+#4 = warn
+#5 = notice
+#6 = info
+#7 = debug
+loglevel = 5
+
+#myMPD user
+#group = mympd
+user = mympd
+
+#Usage of stickers for play statistics
+stickers = false
+
+#Mixrampdb settings in gui
+mixramp = false
+
+#Enable system commands defined in syscmds section
+syscmds = false
+
+#Enable lua scripting
+#scripting = false
+
+#Chroot to /var/lib/mympd
+chroot = false
+readonly = false
+
+smartpls = false
+autoplay = true
+
+[syscmds]
+Shutdown = sudo /sbin/halt
+#To use this command add following lines to /etc/sudoers (without #)
+#Cmnd_Alias MYMPD_CMDS = /sbin/halt
+#mympd ALL=NOPASSWD: MYMPD_CMDS
+
diff --git a/resources/scripts/alsa_unmute b/resources/scripts/alsa_unmute
new file mode 100755
index 0000000000000000000000000000000000000000..a8ac60909347b0f5c6504483a6af27acbf60a51d
--- /dev/null
+++ b/resources/scripts/alsa_unmute
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+for CARD in /proc/asound/card*; do
+  if [ -d ${CARD} ]; then
+    ID=$(echo $CARD|sed -e "s/\/proc\/asound\/card\(.*\)/\1/g")
+    echo "Card: $CARD ID: $ID"
+  
+    amixer -c ${ID} scontrols |
+    while IFS= read -r line
+    do
+      DEVICE=`echo ${line}| awk -F\' '{print $2}'`
+      LOWER=`echo ${DEVICE}|tr '[:upper:]' '[:lower:]'`
+    
+      # How do I build up these into a OR?
+      if [[ "${LOWER}" == *"capture"* ]]; then
+        continue;
+      elif [[ "${LOWER}" == *"mic"* ]]; then
+        continue
+      elif [[ "${LOWER}" == *"mute"* ]]; then
+        continue;
+      elif [[ "${LOWER}" == *"input"* ]]; then
+        continue;
+      elif [[ "${DEVICE}" == "IEC958 Loopback" ]]; then
+        continue;
+      fi
+
+      amixer sset "${DEVICE}" 100% unmute nocap > /dev/null 2> /dev/null
+    done
+  fi
+done
+
diff --git a/resources/scripts/init b/resources/scripts/init
new file mode 100755
index 0000000000000000000000000000000000000000..a7c048977103480d578ab551195a9490c86df42b
--- /dev/null
+++ b/resources/scripts/init
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+# This should be first
+if [ ! -f "/var/www/config/machine_address" ]; then
+  COUNT=0;
+  while true; do
+    if [ "${COUNT}" -gt "20" ]; then
+      break;
+    fi
+    echo $(dd if=/dev/urandom bs=1024 count=1 2>/dev/null|md5sum|\
+       sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/00:\2:\3:\4:\5:\6/') >> \
+          "/var/www/config/machine_address"
+    ((++COUNT))
+  done
+fi
+
+# Update file permissions
+if [ ! -d /media/music ]; then
+  mkdir /media/music
+fi
+
+if [ ! -d /media/playlists ]; then
+  mkdir /media/playlists
+fi
+
+if [ ! -d /var/www/config ]; then
+  mkdir /var/www/html/config
+fi
+
+if [ ! -d /var/www/scratch ]; then
+  mkdir /var/www/html/scratch
+fi
+
+if [ ! -f /etc/init/ssh.override ]; then
+  touch /etc/init/ssh.override
+fi
+
+if [ ! -f /etc/init/tty1.override ]; then
+  touch /etc/init/tty1.override
+fi
+
+if [ ! -f /etc/init/smbd.override ]; then
+  touch /etc/init/smbd.override
+fi
+
+if [ ! -f /etc/init/nmbd.override ]; then
+  touch /etc/init/nmbd.override
+fi
+
+rm -f /etc/lighttpd/conf-enabled/50-snakeoil.conf
+
+if [ ! -L /var/www/music ]; then
+  ln -s /media/music/ /var/www/music
+fi
+
+chown www-data:www-data /var/www/html/scratch -R
+chown www-data:www-data /var/www/html/config -R
+chown www-data:root     /etc/init/tty1.override 
+chown www-data:root     /etc/init/ssh.override
+chown www-data:root     /etc/init/smbd.override 
+chown www-data:root     /etc/init/nmbd.override 
+chown www-data:root     /etc/network/interfaces
+chown www-data:root     /etc/hostname
+chown www-data:root     /etc/hosts
+chown www-data:www-data /media/music 
+chown www-data:www-data /media/playlists 
+chown www-data:www-data /var/www/html/players/mpd*/data/* 
+
+chmod a+s /var/www/html/players/mpd-dsd-rt/mpd
+chmod a+s /var/www/html/players/mpd-v20/mpd
+
+chmod 664 /etc/init/tty1.override
+chmod 666 /var/www/html/players/mpd*/data/* 
+
+if grep -Fxq "yes" /var/www/config/start_ssh ; then
+  service ssh restart 2>/dev/null > /dev/null
+else
+  service ssh stop 2>/dev/null > /dev/null
+fi
+
+if [ -f /var/www/config/process ]; then
+  /var/www/cgi/chprio
+fi
+
+if [ -f /etc/udev/rules.d/70-persistent-net.rules ] && [ "`/var/www/cgi/show_avail_nic |grep -o "~" | wc -l`" -eq 1 ]; then
+  rm /etc/udev/rules.d/70-persistent-net.rules -fv
+fi
+
+/bin/su www-data -c /var/www/cgi/stop_player
+/bin/su www-data -c /var/www/cgi/start_player
+
+if [ -f /var/www/config/process ]; then
+  /var/www/cgi/chprio
+fi
+
+sysctl fs.inotify.max_user_watches=32768 > /dev/null
+
+/usr/local/bin/new_issues
diff --git a/resources/scripts/minimserver_remote.sh b/resources/scripts/minimserver_remote.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b665475372aee5887f6724cf044f82100a81e005
--- /dev/null
+++ b/resources/scripts/minimserver_remote.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+HOST=$(hostname -I|awk '{print $1}')
+if [ -z "$HOSTNAME" ]; then
+  HOST=$(hostname)
+fi
+echo "{\"url\": \"http://$HOST:9790/\", \"name\": \"minimserver\"}"
diff --git a/resources/scripts/mpd_remote.sh b/resources/scripts/mpd_remote.sh
new file mode 100755
index 0000000000000000000000000000000000000000..533c114b7a9b7ddb2ea83c2802d1ae2ec42c0e86
--- /dev/null
+++ b/resources/scripts/mpd_remote.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+if [ $# -eq 0 ]; then
+  # no argument, assuming returning remote
+  MODE="REMOTE"
+else
+  MODE=($1)
+fi
+
+# Convert mode to lower case
+MODE=${MODE,,}
+# User to run mympd
+
+if [ "$MODE" == "start" ]; then
+  # Wait for MPD to start
+  RUNNING=""
+  COUNT=0
+  while [ ${COUNT} -lt 60 ]; do
+    RUNNING=$(netstat -an|grep 6600|grep LISTEN)
+    if [ ! -z "${RUNNING}" ]; then
+      mympd 2>> /tmp/stderr  >> /tmp/stdout &
+      break
+    fi
+    ((COUNT++))
+    sleep 1
+  done
+elif [ "$MODE" == "stop" ]; then
+  COUNT=0
+  PID=$(pgrep ^mympd)
+  while [ ! -z "$PID" ]; do
+    kill -9 $PID
+    ((COUNT++))
+    if [ $COUNT -gt 5 ]; then
+      break
+    elif [ $COUNT -gt 2 ]; then
+      sleep 0.5
+    fi
+    PID=$(pgrep ^mympd)
+  done
+else
+  HOST=$(hostname -I|awk '{print $1}')
+  if [ -z "$HOSTNAME" ]; then
+    HOST=$(hostname)
+  fi
+  echo "{\"url\": \"http://$HOST:8080/\", \"name\": \"myMPD\"}"
+fi
+
diff --git a/resources/scripts/new_issue b/resources/scripts/new_issue
new file mode 100755
index 0000000000000000000000000000000000000000..598078d0ba851aaa4e810dcf5c6b7facaa3ad442
--- /dev/null
+++ b/resources/scripts/new_issue
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+IP=$(hostname -I)
+SNAKEOIL=`wget -O - http://localhost:30511/api/version 2> /dev/null`
+ISSUE="SnakeoilOS ${SNAKEOIL:12:-2}"
+
+echo -e "IP Address: ${IP}\n$ISSUE" > /etc/issue
+echo "$ISSUE" > /etc/issue.net
+
diff --git a/resources/smb.conf b/resources/smb.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7e35188a2ec6475232d13d038795d91080dd42b9
--- /dev/null
+++ b/resources/smb.conf
@@ -0,0 +1,290 @@
+#
+# Sample configuration file for the Samba suite for Debian GNU/Linux.
+#
+#
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options most of which
+# are not shown in this example
+#
+# Some options that are often worth tuning have been included as
+# commented-out examples in this file.
+#  - When such options are commented with ";", the proposed setting
+#    differs from the default Samba behaviour
+#  - When commented with "#", the proposed setting is the default
+#    behaviour of Samba but the option is considered important
+#    enough to be mentioned here
+#
+# NOTE: Whenever you modify this file you should run the command
+# "testparm" to check that you have not made any basic syntactic
+# errors.
+
+#======================= Global Settings =======================
+
+[global]
+
+## Browsing/Identification ###
+
+# Change this to the workgroup/NT-domain name your Samba server will part of
+   workgroup = WORKGROUP
+
+# server string is the equivalent of the NT Description field
+        server string = %h server (Samba, Ubuntu)
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable its WINS Server
+#   wins support = no
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+;   wins server = w.x.y.z
+
+# This will prevent nmbd to search for NetBIOS names through DNS.
+   dns proxy = no
+
+#### Networking ####
+
+# The specific set of interfaces / networks to bind to
+# This can be either the interface name or an IP address/netmask;
+# interface names are normally preferred
+;   interfaces = 127.0.0.0/8 eth0
+
+# Only bind to the named interfaces and/or networks; you must use the
+# 'interfaces' option above to use this.
+# It is recommended that you enable this feature if your Samba machine is
+# not protected by a firewall or is a firewall itself.  However, this
+# option cannot handle dynamic or non-broadcast interfaces correctly.
+;   bind interfaces only = yes
+
+
+
+#### Debugging/Accounting ####
+
+# This tells Samba to use a separate log file for each machine
+# that connects
+   log file = /var/log/samba/log.%m
+
+# Cap the size of the individual log files (in KiB).
+   max log size = 1000
+
+# If you want Samba to only log through syslog then set the following
+# parameter to 'yes'.
+#   syslog only = no
+
+# We want Samba to log a minimum amount of information to syslog. Everything
+# should go to /var/log/samba/log.{smbd,nmbd} instead. If you want to log
+# through syslog you should set the following parameter to something higher.
+   syslog = 0
+
+# Do something sensible when Samba crashes: mail the admin a backtrace
+   panic action = /usr/share/samba/panic-action %d
+
+
+####### Authentication #######
+
+# Server role. Defines in which mode Samba will operate. Possible
+# values are "standalone server", "member server", "classic primary
+# domain controller", "classic backup domain controller", "active
+# directory domain controller".
+#
+# Most people will want "standalone sever" or "member server".
+# Running as "active directory domain controller" will require first
+# running "samba-tool domain provision" to wipe databases and create a
+# new domain.
+   server role = standalone server
+
+# If you are using encrypted passwords, Samba will need to know what
+# password database type you are using.
+   passdb backend = tdbsam
+
+   obey pam restrictions = yes
+
+# This boolean parameter controls whether Samba attempts to sync the Unix
+# password with the SMB password when the encrypted SMB password in the
+# passdb is changed.
+   unix password sync = yes
+
+# For Unix password sync to work on a Debian GNU/Linux system, the following
+# parameters must be set (thanks to Ian Kahan <<kahan@informatik.tu-muenchen.de> for
+# sending the correct chat script for the passwd program in Debian Sarge).
+   passwd program = /usr/bin/passwd %u
+   passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
+
+# This boolean controls whether PAM will be used for password changes
+# when requested by an SMB client instead of the program listed in
+# 'passwd program'. The default is 'no'.
+   pam password change = yes
+
+# This option controls how unsuccessful authentication attempts are mapped
+# to anonymous connections
+   map to guest = bad user
+
+########## Domains ###########
+
+#
+# The following settings only takes effect if 'server role = primary
+# classic domain controller', 'server role = backup domain controller'
+# or 'domain logons' is set
+#
+
+# It specifies the location of the user's
+# profile directory from the client point of view) The following
+# required a [profiles] share to be setup on the samba server (see
+# below)
+;   logon path = \\%N\profiles\%U
+# Another common choice is storing the profile in the user's home directory
+# (this is Samba's default)
+#   logon path = \\%N\%U\profile
+
+# The following setting only takes effect if 'domain logons' is set
+# It specifies the location of a user's home directory (from the client
+# point of view)
+;   logon drive = H:
+#   logon home = \\%N\%U
+
+# The following setting only takes effect if 'domain logons' is set
+# It specifies the script to run during logon. The script must be stored
+# in the [netlogon] share
+# NOTE: Must be store in 'DOS' file format convention
+;   logon script = logon.cmd
+
+# This allows Unix users to be created on the domain controller via the SAMR
+# RPC pipe.  The example command creates a user account with a disabled Unix
+# password; please adapt to your needs
+; add user script = /usr/sbin/adduser --quiet --disabled-password --gecos "" %u
+
+# This allows machine accounts to be created on the domain controller via the
+# SAMR RPC pipe.
+# The following assumes a "machines" group exists on the system
+; add machine script  = /usr/sbin/useradd -g machines -c "%u machine account" -d /var/lib/samba -s /bin/false %u
+
+# This allows Unix groups to be created on the domain controller via the SAMR
+# RPC pipe.
+; add group script = /usr/sbin/addgroup --force-badname %g
+
+############ Misc ############
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+;   include = /home/samba/etc/smb.conf.%m
+
+# Some defaults for winbind (make sure you're not using the ranges
+# for something else.)
+;   idmap uid = 10000-20000
+;   idmap gid = 10000-20000
+;   template shell = /bin/bash
+
+# Setup usershare options to enable non-root users to share folders
+# with the net usershare command.
+
+# Maximum number of usershare. 0 (default) means that usershare is disabled.
+;   usershare max shares = 100
+
+# Allow users who've been granted usershare privileges to create
+# public shares, not just authenticated ones
+   usershare allow guests = yes
+
+#======================= Share Definitions =======================
+
+# Un-comment the following (and tweak the other settings below to suit)
+# to enable the default home directory shares. This will share each
+# user's home directory as \\server\username
+;[homes]
+;   comment = Home Directories
+;   browseable = no
+
+# By default, the home directories are exported read-only. Change the
+# next parameter to 'no' if you want to be able to write to them.
+;   read only = yes
+
+# File creation mask is set to 0700 for security reasons. If you want to
+# create files with group=rw permissions, set next parameter to 0775.
+;   create mask = 0700
+
+# Directory creation mask is set to 0700 for security reasons. If you want to
+# create dirs. with group=rw permissions, set next parameter to 0775.
+;   directory mask = 0700
+
+# By default, \\server\username shares can be connected to by anyone
+# with access to the samba server.
+# Un-comment the following parameter to make sure that only "username"
+# can connect to \\server\username
+# This might need tweaking when using external authentication schemes
+;   valid users = %S
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+# (you need to configure Samba to act as a domain controller too.)
+;[netlogon]
+;   comment = Network Logon Service
+;   path = /home/samba/netlogon
+;   guest ok = yes
+;   read only = yes
+
+# Un-comment the following and create the profiles directory to store
+# users profiles (see the "logon path" option above)
+# (you need to configure Samba to act as a domain controller too.)
+# The path below should be writable by all users so that their
+# profile directory may be created the first time they log on
+;[profiles]
+;   comment = Users profiles
+;   path = /home/samba/profiles
+;   guest ok = no
+;   browseable = no
+;   create mask = 0600
+;   directory mask = 0700
+
+[printers]
+   comment = All Printers
+   browseable = no
+   path = /var/spool/samba
+   printable = yes
+   guest ok = no
+   read only = yes
+   create mask = 0700
+
+# Windows clients look for this share name as a source of downloadable
+# printer drivers
+[print$]
+   comment = Printer Drivers
+   path = /var/lib/samba/printers
+   browseable = yes
+   read only = yes
+   guest ok = no
+# Uncomment to allow remote administration of Windows print drivers.
+# You may need to replace 'lpadmin' with the name of the group your
+# admin users are members of.
+# Please note that you also need to set appropriate Unix permissions
+# to the drivers directory for these users to have write rights in it
+;   write list = root, @lpadmin
+
+[playlists]
+  path = /media/playlists
+  comment = Put all your playlists here
+  available = yes
+  ##valid users = guest
+  guest ok = yes
+  read only = no
+  browseable = yes
+  public = yes
+  writable = yes
+  create mask = 0777
+  available = Yes
+  create mode = 0644
+  directory mode = 0755
+
+[music]
+  path = /media/music
+  comment = Put all your Music here
+  available = yes
+  ##valid users = guest
+  guest ok = yes
+  read only = no
+  browseable = yes
+  public = yes
+  writable = yes
+  create mask = 0777
+  available = Yes
+  create mode = 0644
+  directory mode = 0755
+
diff --git a/resources/sudoers.d/build_snakeoil b/resources/sudoers.d/build_snakeoil
new file mode 100644
index 0000000000000000000000000000000000000000..adbeeab73d9a8c7ce9e7f2e8ee8e365cdf328c53
--- /dev/null
+++ b/resources/sudoers.d/build_snakeoil
@@ -0,0 +1 @@
+gitlab-runner ALL = (ALL) NOPASSWD: /sbin/parted, /sbin/losetup, /sbin/resize2fs, /sbin/e2fsck, /usr/sbin/zerofree, /bin/cp, /bin/rm, /bin/sed, /usr/bin/tee, /usr/bin/touch, /usr/sbin/chroot, /usr/bin/mksquashfs,/usr/bin/du, /bin/chmod, /bin/chown, /bin/mkdir
diff --git a/resources/template/installer.template b/resources/template/installer.template
new file mode 100644
index 0000000000000000000000000000000000000000..6af2afca454260d1f93e03efe57c1f5b04eb495b
--- /dev/null
+++ b/resources/template/installer.template
@@ -0,0 +1,665 @@
+#!/usr/bin/env bash
+TMPDIR=''
+OUTPUT=$(mktemp)
+VERSION="@VERSION@"
+
+ARC_BEG=@ARC_BEG@
+BLOB_SUM=@BLOB_SUM@
+ARC_SUM=@ARC_SUM@
+API_SUM=@API_SUM@
+LMS_SUM=@LMS_SUM@
+
+LMS=@LMS@
+
+ALREADY_INSTALLED="Already installed"
+
+function error_out() {
+  echo " !!!!! ERROR !!!!!"
+  echo "$1"
+  exit 1
+}
+
+echo "# Begin installation of Snakeoil ${VERSION} "
+###############################################################################
+## Verify components
+## $1 name
+## $2 file
+## $3 checksum to verify file again
+###############################################################################
+function verify_checksum() {
+  if [ ! $# -eq 3 ]; then
+    echo "# Error calling verify_checksum function: $#"
+    quit 1
+  fi
+  echo -n "    - verifying component: ${1}... "
+  if [ -f ${2} ]; then
+  CHKSUM=$(sha1sum ${2} | awk '{print $1}')
+  fi
+  if [ ${CHKSUM} == $3 ]; then
+    echo "OK"
+  else
+    echo "ERROR"
+    error_out "Checksum failed"
+  fi
+}
+
+###############################################################################
+##
+## Try and identify distro
+##
+###############################################################################
+function identify_distro() {
+  DISTRO=$(which lsb_release)
+  if [ $? -eq 0 ]; then
+    DISTRO=$(lsb_release -i|awk '{print $3}')
+  fi
+
+  echo "${DISTRO}"
+}
+
+
+###############################################################################
+##
+## Version compare
+## 0 = Version match
+## 1 = $1 is greater than $2
+## 2 = $1 is less than $2
+##
+###############################################################################
+vercomp () {
+    if [[ $1 == $2 ]]
+    then
+        return 0
+    fi
+    local IFS=.
+    local i ver1=($1) ver2=($2)
+    # fill empty fields in ver1 with zeros
+    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
+    do
+        ver1[i]=0
+    done
+    for ((i=0; i<${#ver1[@]}; i++))
+    do
+        if [[ -z ${ver2[i]} ]]
+        then
+            # fill empty fields in ver2 with zeros
+            ver2[i]=0
+        fi
+        if ((10#${ver1[i]} > 10#${ver2[i]}))
+        then
+            return 1
+        fi
+        if ((10#${ver1[i]} < 10#${ver2[i]}))
+        then
+            return 2
+        fi
+    done
+    return 0
+}
+
+###############################################################################
+##
+## Returns true if program is found
+##
+###############################################################################
+
+function program_exists() {
+  echo -n "    * Checking program ($1)... "
+  MSGS=$(which $1)
+  if [ $? -eq 0 ]; then
+    echo "FOUND"
+  else
+    echo "MISSING. please install $1"
+    echo "# Snakeoil installation aborted"
+    exit 1
+  fi
+}
+
+die() { echo "$*" >&2; exit 2; }  # complain to STDERR and exit with error
+needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }
+
+APT_UPDATE="yes"
+###############################################################################
+## Check commandline arguments
+###############################################################################
+function process_options() {
+while getopts hn-: OPT;
+do
+  # support long options: https://stackoverflow.com/a/28466267/519360
+  if [ "$OPT" = "-" ]; then   # long option: reformulate OPT and OPTARG
+    OPT="${OPTARG%%=*}"       # extract long option name
+    OPTARG="${OPTARG#$OPT}"   # extract long option argument (may be empty)
+    OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
+  fi
+
+  case "${OPT}" in
+    h | help )
+       echo -e "Snakeoil Installer ${VERSION}\n"
+       echo "[options]"
+       echo "          -h | --help: Show this help"
+       echo " -n | --no-apt-update: Skip apt update"
+       exit 0
+       ;;
+    n | no-apt-update)
+       APT_UPDATE="no";;
+   ??*) die "Illegal option --$OPT" ;;  # bad long option
+     ?) exit 2 ;;  # bad short option (error reported via getopts)
+  esac
+done
+}
+
+###############################################################################
+##
+## Check for dependencies
+##
+## Needs tar, head, tail, xz
+###############################################################################
+function check_prerequisites() {
+  echo -n "  + Checking pre-requistes... "
+  WHOAMI=$(whoami)
+  if [ "${WHOAMI}" != "root" ]; then
+    echo -e "Error. Install aborted!\n    * !!! Need to run script with sudo rights !!!"
+    quit 1
+  else
+    echo "OK"
+  fi
+
+  if [ ! -f "/usr/bin/which" ]; then
+    echo -e "Error. Install aborted!\n    * Program 'which' is missing. Please install which."
+    quit 1
+  fi
+
+  # ip link show|grep UP |grep -v lo:|head -n 1|cut -d: -f2| xargs)
+  program_exists ip
+  program_exists grep
+  program_exists head
+  program_exists tail
+  program_exists sed
+  program_exists pgrep
+  program_exists sha1sum
+  program_exists tar
+  program_exists ip
+  program_exists cat
+  program_exists mktemp
+  program_exists cut
+  program_exists xargs
+
+  return 0
+}
+
+
+###############################################################################
+##
+##
+##
+###############################################################################
+function copy() {
+  cp "${@}" -rf
+  if [ ${?} -ne 0 ]; then
+    echo "Error"
+    quit 1
+  fi
+}
+
+
+###############################################################################
+##
+## Return 1 if deb is installed, 0 otherwise
+## $1: deb file
+##
+###############################################################################
+function is_deb_installed() {
+  CHECK=$(dpkg -l "${1}" 2> /dev/null|grep ii)
+
+  if [ -z "${CHECK}" ]; then
+    echo "no"
+  else
+    echo "yes"
+  fi
+}
+
+###############################################################################
+## Check if I need to update DEB
+## $1: installed DEB file
+## #2: New DEB file
+###############################################################################
+function is_deb_upgrade() {
+  INSTALL=$(dpkg -l|grep logitechmediaserver|awk '{print $3}'|cut -d~ -f1)
+  UPGRADE=$(echo $2 |cut -d_ -f2|cut -d~ -f1)
+
+  vercomp ${INSTALL} ${UPGRADE}
+  if [ $? -eq 2 ]; then
+    echo "yes"
+  else
+    echo "no"
+  fi
+}
+
+###############################################################################
+##
+## install package via apt
+##
+###############################################################################
+function apt_install() {
+  echo "    * Checking package: ${1}"
+  echo -n -e "      - Status:\r"
+  IS_INSTALLED=$(is_deb_installed ${1})
+
+  if [ "${IS_INSTALLED}" == "no" ]; then
+    echo -e -n "      - Status: Installing... \r"
+    MSGS=$(apt-get --assume-yes install $1 > ${OUTPUT} 2>> ${OUTPUT})
+    
+    if [ $? -eq 0 ]; then
+      rm -f ${OUTPUT}
+      echo "      - Status: Installing... OK"
+    else
+      echo "      - Status: Installing... Failed"
+      cat ${OUTPUT}
+
+      rm -f ${OUTPUT}
+      quit 1
+    fi
+  else
+    echo "      - Status: ${ALREADY_INSTALLED}"
+  fi
+}
+
+###############################################################################
+## Common apt based packages
+###############################################################################
+function install_packages_debian() {
+  echo -n "    * Updating repos... "
+  if [ "${APT_UPDATE}" == "yes" ]; then
+    apt update > /dev/null 2> /dev/null
+    echo "OK"
+  else
+    echo "Skipped"
+  fi
+
+  apt_install net-tools
+  apt_install avahi-daemon
+  apt_install icewm
+  apt_install lighttpd
+  apt_install php-cgi
+  apt_install tigervnc-standalone-server
+  apt_install libio-socket-ssl-perl
+  apt_install libgomp1
+  apt_install cifs-utils
+  apt_install nfs-common
+  apt_install samba
+  apt_install python3-future
+}
+
+###############################################################################
+## For Raspbian
+###############################################################################
+function install_packages_raspbian(){
+  install_packages_debian
+
+  return 0
+}
+
+
+###############################################################################
+## For Ubuntu
+###############################################################################
+function install_packages_ubuntu() {
+  install_packages_debian
+
+  # Other Ubuntu specific pages to install
+  apt_install openssh-server
+
+  return 0
+}
+
+
+###############################################################################
+##
+## Nice way of quitting
+##
+###############################################################################
+function quit() {
+  if [ -d "${TMPDIR}" ]; then
+    echo -n "# Cleaning up tmp files... "
+    rm -rf ${TMPDIR}
+    echo "OK"
+  fi
+
+  if [ -f ${OUTPUT} ]; then
+    rm -f ${OUTPUT}
+  fi
+
+  if [ ${1} -ne 0 ]; then
+    echo "# Install aborted with errors!"
+  else
+    # Check if snakeoil is already running. If PID exist this is likely
+    # to be a pre-installed system
+    PID_SNAKEOIL=$(pgrep snakeoil-rest)
+    if [ -z "${PID_SNAKEOIL}" ]; then
+        echo "# Installation complete. Please reboot your computer now."
+    else
+      /usr/local/sbin/snakeoil-rest --exit > /dev/null 2> /dev/null
+      echo "# Installation complete."
+      echo "# Restarting Snakeoil RestAPI server."
+      echo "# Please wait at least 1 minute before trying the WebApp"
+    fi
+  fi
+
+  exit ${1}
+}
+
+###############################################################################
+##
+## Install distro packages
+##
+###############################################################################
+function install_packages() {
+  DISTRO=$(identify_distro)
+
+  echo "  + System identified as: ${DISTRO}"
+  if [ "${DISTRO}" == "Ubuntu" ]; then
+    install_packages_ubuntu
+    if [ $? -ne 0 ]; then
+      echo ${MSGS}
+      quit 1
+    fi
+  elif [ "${DISTRO}" == "Raspbian" ]; then
+    install_packages_raspbian
+    if [ $? -ne 0 ]; then
+      echo ${MSGS}
+      quit 1
+    fi
+  else
+    echo "  + This distro is not supported yet. Install aborted."
+    quit 1
+  fi
+}
+
+###############################################################################
+##
+## Install Snakeoil packages
+##
+###############################################################################
+function install_snakeoil() {
+  TMPDIR=$(mktemp -d)
+  echo -n "  + Creating media folders... "
+  mkdir -p /media/music
+  mkdir -p /media/playlists
+  echo "OK"
+
+  echo -n "  + Checking installer integrity... "
+  tail -n +${ARC_BEG} "$0" > ${TMPDIR}/archive.tar.bz2
+  EX_ARC_SUM=$(sha1sum ${TMPDIR}/archive.tar.bz2|awk '{print $1}')
+
+  if [ "${EX_ARC_SUM}" != "${ARC_SUM}" ]; then
+    echo "ERROR"
+    error_out "Archive Checksum Error ${EX_ARC_SUM} vs ${ARC_SUM}"
+  else
+    echo "OK"
+  fi
+
+  ## Start to decompress files
+  echo -n "  + Extracting archive... "
+  MSGS=$(tar -xjvf ${TMPDIR}/archive.tar.bz2 --directory ${TMPDIR} > ${OUTPUT} 2>> ${OUTPUT})
+  if [ $? -ne 0 ]; then
+    echo " ERROR"
+    cat ${OUTPUT}
+    error_out "Problem extracting archive"
+  fi
+  echo "OK"
+
+  ## verify components
+  verify_checksum "snakeoil-rest" ${TMPDIR}/snakeoil-rest ${API_SUM}
+  verify_checksum "Logitech Media Server" ${TMPDIR}/${LMS} ${LMS_SUM}
+  verify_checksum "snakeoil blob" ${TMPDIR}/install.blob ${BLOB_SUM}
+
+  ##
+  echo -n "  + Install Snakeoil RestAPI server... "
+  copy ${TMPDIR}/snakeoil-rest "/usr/local/sbin" -f
+  echo "OK"
+
+  ##
+  echo -n "  + Installing Snakeoil blob, please be patient... "
+  BLOB_FILE="/tmp/recover.fw"
+  copy ${TMPDIR}/install.blob "${BLOB_FILE}"
+  if [ ! -f "${BLOB_FILE}"  ]; then
+    echo " ERROR"
+    echo "   No write permissions or free space to install"
+    quit 1
+  fi
+  cp ${TMPDIR}/snakeoil-rest /tmp
+  /tmp/snakeoil-rest --recover=${BLOB_FILE} > /tmp/snakeoil-install.log
+  if [ $? -eq 0 ]; then
+    rm -f /tmp/snakeoil-rest
+    echo "OK"
+  else
+    rm -f /tmp/snakeoil-rest
+    echo "ERROR"
+    quit 1
+  fi
+}
+
+
+###############################################################################
+##
+## Install Snakeoil packages
+##
+###############################################################################
+function config_snakeoil() {
+  echo "# Prepping Your System For Snakeoil."""
+  echo -n "  + Startup script... "
+
+  echo -e "#!/bin/bash
+  # Last updated: 2020-02-28
+  PID=\$(pidof -x \"snakeoil-server.sh\")
+  if [ \"\${PID}\" != \"\$\$\" ]; then
+    echo \"Snakeoil-server script already running\"
+    exit 1
+  fi
+
+  snakeoil-rest --exit
+
+  rm /tmp/stderr -f
+  rm /tmp/stdout -f
+
+  while true; do
+    if [ -f /media/music/snakeoil-rest ]; then
+      mv -f /media/music/snakeoil-rest /usr/local/sbin/snakeoil-rest
+      chown root:root /usr/local/sbin/snakeoil-rest
+      chmod 755 /usr/local/sbin/snakeoil-rest
+    fi
+
+    if [ -f /media/music/snakeoil-runme.sh ]; then
+      sh /media/music/snakeoil-runme.sh
+      if [ $? -eq 0 ]; then
+        rm -rf /media/music/snakeoil-runme.sh
+      fi
+    fi
+
+    HOME=/root/ USER=root /usr/local/sbin/snakeoil-rest 2>> /tmp/stderr >> /tmp/stdout
+    sleep 1
+  done" > /usr/local/bin/snakeoil-server.sh
+
+  chmod 755 /usr/local/bin/snakeoil-server.sh
+
+  # Check if /etc/rc.local already exists, create if missing
+  if [ ! -f "/etc/rc.local" ]; then
+    echo -e "#!/bin/bash\n\nexit 0\n" > /etc/rc.local
+  fi
+  chmod 755 /etc/rc.local
+  NEW_ISSUE=$(grep new_issue /etc/rc.local)
+  SNAKEOIL_SCRIPT=$(grep snakeoil-server.sh /etc/rc.local)
+
+  if [ -f "/etc/systemd/system/rc-local.service" ] && [ -f "/etc/rc.local" ] \
+          && [ ! -z "${NEW_ISSUE}" ] && [ ! -z "${SNAKEOIL_SCRIPT}" ]; then
+    echo "${ALREADY_INSTALLED}"
+  else
+    # check if "/etc/systemd/system/rc-local.service" exists, and create if missing
+    if [ ! -f "/etc/systemd/system/rc-local.service" ]; then
+      echo -e "[Unit]\n\tDescription=/etc/rc.local Compatibility\n\tConditionPathExists=/etc/rc.local\n\n[Service]\n\tType=forking\n\tExecStart=/etc/rc.local start\n\tTimeoutSec=0\n\tStandardOutput=tty\n\tRemainAfterExit=yes\n\tSysVStartPriority=99\n\n[Install]\n\tWantedBy=multi-user.target\n" > "/etc/systemd/system/rc-local.service"
+    fi
+
+    if [ -z "${NEW_ISSUE}" ]; then
+      INSERT="\nsleep 5 && /usr/local/bin/new_issue &\n"
+    fi
+    if [ -z "${SNAKEOIL_SCRIPT}" ]; then
+      INSERT="${INSERT}\n/usr/local/bin/snakeoil-server.sh &\n"
+    fi
+    RC_LOCAL_LINES=$(wc -l /etc/rc.local | awk '{print $1}')
+
+    START=$(grep ^"exit 0" /etc/rc.local -n|cut -d: -f1)
+    if [ -z "${START}" ]; then
+      START="1"
+    else
+      if [ ${START} -gt 0 ]; then
+        START=$(expr ${START} - 1)
+      fi 
+    fi
+    CONTINUE=$(expr ${RC_LOCAL_LINES} - ${START})
+
+    RC_LOCAL_HEAD=$(head -n${START} /etc/rc.local)
+    RC_LOCAL_TAIL=$(tail -n${CONTINUE} /etc/rc.local)
+    echo -e "${RC_LOCAL_HEAD}\n${INSERT}\n${RC_LOCAL_TAIL}" > /etc/rc.local
+
+    #enable rc-local to start on load
+    MSGS=$(systemctl enable rc-local > /dev/null 2> /dev/null)
+    echo "OK"
+  fi
+
+  echo -n "  + Web server... "
+  MSGS=$(sed -i /etc/lighttpd/lighttpd.conf -e "s/^\(server\.document-root.*=.*\).*/server\.document-root        = \"\/var\/www\/\"/g")
+  lighttpd-enable-mod fastcgi > /dev/null 2> /dev/null
+  lighttpd-enable-mod fastcgi-php 2> /dev/null > /dev/null
+  lighttpd-enable-mod proxy   > /dev/null 2> /dev/null
+  lighttpd-enable-mod rewrite > /dev/null 2> /dev/null
+  API_PORT=$(grep 30511 /etc/lighttpd/lighttpd.conf)
+  if [ -z "${API_PORT}" ]; then
+    echo -e "\nproxy.server = (\n  \"/api\" => ( (\n    \"host\" => \"127.0.0.1\",\n    \"port\" => 30511\n  ) )\n )\n\n" >> /etc/lighttpd/lighttpd.conf
+  fi
+  REWRITE=$(grep rewrite\-if\-not\-file /etc/lighttpd/lighttpd.conf)
+
+  if [ -z "${REWRITE}" ]; then
+    echo -e "\nurl.rewrite-if-not-file = ( \"(?!\\.\\w+\$)\" => \"/index.html\" )\n" >> /etc/lighttpd/lighttpd.conf
+  fi
+
+  systemctl restart lighttpd
+  if [ $? -eq 0 ]; then
+    echo "OK"
+  else
+    echo "ERROR"
+    error_out "Cannot restart Lighttpd server"
+  fi
+
+  ## LMS
+  echo -n "  + Logitech Media Server... "
+  IS_INSTALLED=$(is_deb_installed logitechmediaserver)
+  NEEDS_UPGRADE=$(is_deb_upgrade "logitechmediaserver" "${LMS}")
+
+  if [ "${IS_INSTALLED}" == "no" ] || [ "${NEEDS_UPGRADE}" == "yes" ]; then
+    MSGS=$(dpkg -i ${TMPDIR}/${LMS} > ${OUTPUT} 2>> ${OUTPUT})
+    if [ $? -ne 0 ]; then
+      echo "ERROR"
+      cat ${OUTPUT}
+      error_out "Cannot install LMS"
+    else 
+      echo "OK"
+    fi
+  else
+    echo "${ALREADY_INSTALLED}"
+  fi
+  MSGS=$(systemctl disable logitechmediaserver > ${OUTPUT} 2>> ${OUTPUT})
+
+  ## Check network
+  echo -n "  + Configuring network... "
+  INTERFACE=$(ip link show|grep UP |grep -v lo:|head -n 1|cut -d: -f2| xargs)
+  if [ -z "${INTERFACE}" ]; then
+    echo "Cannot detect interface, this might not work"
+  else
+    NETWORK_CONFIG=""
+    FOUND=""
+    if [ -d /etc/netplan ]; then
+      files=$(shopt -s nullglob dotglob; echo /etc/netplan/*)
+      if [ ${#files} -gt 0  ]; then
+        FILE=$(grep "${INTERFACE}" /etc/netplan/* -l | head -n1)
+        if [ ! -z "${FILE}" ]; then
+          sed -i ${FILE} -e "s/${INTERFACE}/eth0/g" > ${OUTPUT} 2>> ${OUTPUT}
+          FOUND="netplan"
+        fi
+      fi
+    fi
+
+    if [ -z "${FOUND}" ] && [ -f /etc/network/interfaces ]; then
+      sed -i /etc/network/interfaces -e "s/${INTERFACE}/eth0/g" > ${OUTPUT} 2>> ${OUTPUT}
+      FOUND="ifupdown"
+    fi
+
+    if [ -z "${FOUND}" ]; then
+      echo "Not using netplan or ifupdown. This might not work"
+    else
+      echo "${FOUND} detected, interface ${INTERFACE}. OK"
+    fi
+  fi
+  ## 
+
+  echo -n "  + Configuring virtual desktop... "
+  mkdir -p /root/.icewm
+  echo -e "#!/bin/bash\n\nPLAYER=\$(cat /var/www/config/player)\nsource \"/var/www/players/\${PLAYER}/config\"\n\nif [ \"\${START_VNC}\" == \"1\" ]; then\n  /var/www/players/\${PLAYER}/\${PLAYER_START} &\nfi\n\nexit 0\n" > /root/.icewm/startup
+  chmod 755 /root/.icewm/startup
+
+  if [ ! -f /root/.dmrc ]; then
+    echo -e "[Desktop]\nSession=icewm-session\n" > /root/.dmrc
+  fi
+  echo "OK"
+
+  ## grub
+  echo -n "  + Configuring boot options... "
+  if [ -f /etc/default/grub ]; then
+    MSGS=$(sed -i /etc/default/grub -e "s/.*GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"text clocksource=hpet 3 biosdevname=0 net.ifnames=0\"/g" && update-grub > ${OUTPUT} 2>> ${OUTPUT})
+    if [ $? -eq 0 ]; then
+      echo "OK"
+    else
+      echo "ERROR"
+      cat "${OUTPUT}"
+      error_out "Cannot setup boot options"
+    fi
+  elif [ -f "/lib/systemd/system/getty@.service" ]; then
+    #Raspbian
+    systemctl set-default multi-user.target
+    if [ ! -f /etc/systemd/system/getty.target.wants/getty@tty1.service ]; then
+      ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty1.service > /dev/null 2> /dev/null
+    fi
+    if [ -f tty1.service.d/autologin.conf ]; then
+      rm /etc/systemd/system/getty@tty1.service.d/autologin.conf
+    fi
+    echo "OK"
+  else
+    echo "Skipped"
+  fi
+
+  echo -n "  + Configuring samba... "
+  if [ -f ${TMPDIR}/smb.conf ]; then
+    if [ ! -d /etc/samba ]; then
+      mkdir -p /etc/samba
+    fi
+    cp ${TMPDIR}/smb.conf /etc/samba
+    systemctl restart smbd 2> /dev/null > /dev/null
+  fi
+  echo "OK"
+
+  return 0
+}
+
+
+###############################################################################
+##
+## As close to main function as I'm gonna get
+##
+###############################################################################
+process_options "${@}"
+check_prerequisites
+install_packages
+install_snakeoil
+config_snakeoil
+
+quit 0
+
diff --git a/resources/toprc b/resources/toprc
new file mode 100644
index 0000000000000000000000000000000000000000..f6839c672764acb50badc04a85f8724e262349de
--- /dev/null
+++ b/resources/toprc
@@ -0,0 +1,15 @@
+top's Config File (Linux processes with windows)
+Id:i, Mode_altscr=0, Mode_irixps=1, Delay_time=3.0, Curwin=0
+Def	fieldscur=���������&')*+,-./012568<>?ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij
+	winflags=161076, sortindx=18, maxtasks=0, graph_cpus=0, graph_mems=0
+	summclr=1, msgsclr=1, headclr=3, taskclr=1
+Job	fieldscur=�����(���@<��)*+,-./012568>?ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij
+	winflags=193844, sortindx=0, maxtasks=0, graph_cpus=0, graph_mems=0
+	summclr=6, msgsclr=6, headclr=7, taskclr=6
+Mem	fieldscur=���<�����MBN�D34��&'()*+,-./0125689FGHIJKLOPQRSTUVWXYZ[\]^_`abcdefghij
+	winflags=193844, sortindx=21, maxtasks=0, graph_cpus=0, graph_mems=0
+	summclr=5, msgsclr=5, headclr=4, taskclr=5
+Usr	fieldscur=�����������)+,-./1234568;<=>?@ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij
+	winflags=193844, sortindx=3, maxtasks=0, graph_cpus=0, graph_mems=0
+	summclr=3, msgsclr=3, headclr=2, taskclr=3
+Fixed_widest=0, Summ_mscale=0, Task_mscale=0, Zero_suppress=0
diff --git a/resources/uefi/x86_64_efi.img b/resources/uefi/x86_64_efi.img
new file mode 100644
index 0000000000000000000000000000000000000000..9ef4491d26405ed737f367a50ec3021337d3f9ec
Binary files /dev/null and b/resources/uefi/x86_64_efi.img differ
diff --git a/resources/update_snakeoil.sh b/resources/update_snakeoil.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9698c0c7dd2ae73ef701809e9ba64115f945057c
--- /dev/null
+++ b/resources/update_snakeoil.sh
@@ -0,0 +1,178 @@
+#!/bin/bash
+function backupMPD()
+{
+  if [ -d "$1" ]; then
+    mkdir $2
+    cp "$1"/* "$2"
+  fi
+}
+
+function updatePerm()
+{
+  find /var/www -name $1 -exec chmod 755 {} \;
+}
+
+FW_ARCH=$(cat arch.txt)
+UR_ARCH=$(uname -m)
+
+if [ "$FW_ARCH" != "$UR_ARCH" ]; then
+  echo "Firmware Architecture don't match your system"
+  exit 1;
+fi
+
+TMP_DIR=$(mktemp -d)
+cp /var/www/config/* "$TMP_DIR/" -rf
+
+# For older systems. Copy music database from old location to new
+for D in `find /var/www/players/ -type d -name data`; do
+  if [[ ${D} =~ /var/www/players/mpd-.*/data$ ]]; then
+    X=${D#/var/www/players/}
+    X=${X%/data}
+    backupMPD ${D} $TMP_DIR/${X}
+  fi
+done
+
+# Check if it's old version of Snakeoil
+OLD_SNAKEOIL=0
+if [ -f "/var/www/snakeoil.theme.dark" ] || [ -f "/var/www/snakeoil.theme.blue" ] || [ -f "/var/www/snakeoil.theme.blur" ]; then
+  OLD_SNAKEOIL=1
+fi
+
+# Look for any local players that are disabled
+DISABLED=()
+for PLAYER in `find /var/www/players/ -type f -name *.disabled`; do
+  D=$(dirname $PLAYER)
+  D=${D#/var/www/players/}
+  DISABLED+=(${D})
+done
+
+# Look for any local players that don't exist in firmware, and copy them out
+P_DIR=$(mktemp -d)
+
+for INSTALLED in $(ls /var/www/players); do
+  if [ "$INSTALLED" == "mpd-dsd-018" ]; then 
+    continue
+  fi
+  if [ ! -d "html/players/$INSTALLED" ]; then
+    mv /var/www/players/$INSTALLED $P_DIR
+    echo "ARCHIVE PLAYER: ${INSTALLED}"
+  fi
+done
+
+# Check if it's old version of Snakeoil
+rm /var/www/ -rf
+mkdir /var/www
+
+if [ -d "bin" ]; then
+  cp bin/* /usr/local/bin/ -f
+fi
+
+if [ -f "new_issue" ]; then
+  cp new_issue /usr/local/bin
+fi
+
+rm /var/www/* -f
+cp html/* /var/www/ -R
+
+ln -sf /media/music /var/www/
+
+if [ $OLD_SNAKEOIL -eq 1 ]; then
+  touch /var/www/snakeoil.theme.blue;
+  touch /var/www/snakeoil.theme.dark;
+  touch /var/www/snakeoil.theme.blur;
+fi
+
+if [ ! -d /var/www/scratch ]; then
+  mkdir /var/www/scratch
+fi
+
+mkdir /var/www/config -p
+
+cp $TMP_DIR/* /var/www/config -fr
+
+if [ -d ${P_DIR}/* ]; then
+  mv $P_DIR/* /var/www/players 
+fi
+
+# No need to copy if this file don't exist, e.g. in installer mode.
+if [ -f rest/snakeoil-rest ]; then
+  cp rest/snakeoil-rest /usr/local/sbin -f
+fi
+
+cp toprc ~/.toprc
+cp grub.template /var/www/config
+
+# Re-disable players that have already been disabled
+for PLAYER in  "${DISABLED[@]}"; do
+  sh "/var/www/players/$PLAYER/uninstall.sh"
+done
+
+chown root:root /var/www -R
+
+if [ -d vnc ]; then
+  if [ ! -d /root/.vnc ]; then
+    mkdir /root/.vnc
+  fi
+  cp vnc/* /root/.vnc
+  chmod 600 /root/.vnc/passwd
+  chmod 755 /root/.vnc/xstartup
+fi
+
+if [ -d alsa ]; then
+  cp alsa /usr/local/share -r
+fi
+
+cp mympd.conf /etc/
+
+if [ -f smb.conf ]; then
+  if [ ! -d /etc/samba ]; then
+    mkdir -p /etc/samba
+  fi
+  cp smb.conf /etc/samba
+fi
+
+rm -rf "$TMP_DIR"
+rm -rf "$P_DIR"
+
+# Fix WWW permissions
+find /var/www -type d -exec chmod 755 {} \;
+find /var/www -exec chown www-data:www-data {} \;
+find /var/www -type f -exec chmod 644 {} \;
+ITEMS="squeezelite*;mpd;start*;stop*;install*;uninstall*;init"
+IFS=';'
+for ITEM in ${ITEMS}
+do
+  updatePerm ${ITEM}
+done
+chown root:root /var/www/scratch -R
+chown root:root /var/www/config -R
+chown root:root /etc/mympd.conf
+
+if [ -d /usr/share/mympd ]; then
+  rm -rf /usr/share/mympd 
+fi
+
+mkdir /var/lib/mympd
+
+getent group mympd > /dev/null || groupadd -r mympd
+getent passwd mympd > /dev/null || useradd -r -g mympd -s /bin/false -d /var/lib/mympd mympd
+
+chown mympd:mympd /var/lib/mympd -R
+
+chmod 644 /etc/mympd.conf
+
+# Remove Amark for Ubuntu 19.x and above
+if [ -d "/var/www/players/amarok" ]; then
+  if [ -f /usr/bin/lsb_release ]; then
+    DISTRO=$(lsb_release -a 2> /dev/null|grep Descrip|awk '{print $3}')
+
+    if [[ "$DISTRO" != "16.04"* ]]; then
+      rm /var/www/players/amarok -rf
+    fi
+  fi
+fi
+if [ -d "/var/www/players/HQPlayer" ]; then
+  rm -rf "/var/www/players/HQPlayer"
+fi
+exit 0
+
diff --git a/resources/vnc/passwd b/resources/vnc/passwd
new file mode 100755
index 0000000000000000000000000000000000000000..492d6101b08ab670f84c2324f0cbf5f9572c786c
--- /dev/null
+++ b/resources/vnc/passwd
@@ -0,0 +1 @@
+g�n^Ȋ�Q
\ No newline at end of file
diff --git a/resources/vnc/xstartup b/resources/vnc/xstartup
new file mode 100755
index 0000000000000000000000000000000000000000..039083ac1a036a149c744ede8f4ef33ce0bddca9
--- /dev/null
+++ b/resources/vnc/xstartup
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+xrdb $HOME/.Xresources
+xsetroot -solid grey
+#x-terminal-emulator -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
+#x-window-manager &
+# Fix to make GNOME work
+export XKL_XMODMAP_DISABLE=1
+/etc/X11/Xsession
diff --git a/resources/x86_64/lib/libcurl.so b/resources/x86_64/lib/libcurl.so
new file mode 120000
index 0000000000000000000000000000000000000000..373a73af27acef3429d62737f49156b80f774118
--- /dev/null
+++ b/resources/x86_64/lib/libcurl.so
@@ -0,0 +1 @@
+libcurl.so.4.4.0
\ No newline at end of file
diff --git a/resources/x86_64/lib/libcurl.so.4 b/resources/x86_64/lib/libcurl.so.4
new file mode 120000
index 0000000000000000000000000000000000000000..373a73af27acef3429d62737f49156b80f774118
--- /dev/null
+++ b/resources/x86_64/lib/libcurl.so.4
@@ -0,0 +1 @@
+libcurl.so.4.4.0
\ No newline at end of file
diff --git a/resources/x86_64/lib/libcurl.so.4.4.0 b/resources/x86_64/lib/libcurl.so.4.4.0
new file mode 100755
index 0000000000000000000000000000000000000000..b76bc1844bca349f9f5ec453a7252543d1278611
Binary files /dev/null and b/resources/x86_64/lib/libcurl.so.4.4.0 differ
diff --git a/resources/x86_64/lib/libixml.so b/resources/x86_64/lib/libixml.so
new file mode 120000
index 0000000000000000000000000000000000000000..2e6c09a98f87fb10acdc825e22cc2e5de92890e6
--- /dev/null
+++ b/resources/x86_64/lib/libixml.so
@@ -0,0 +1 @@
+/usr/local/lib/libixml.so.2.0.8
\ No newline at end of file
diff --git a/resources/x86_64/lib/libixml.so.2 b/resources/x86_64/lib/libixml.so.2
new file mode 120000
index 0000000000000000000000000000000000000000..2e6c09a98f87fb10acdc825e22cc2e5de92890e6
--- /dev/null
+++ b/resources/x86_64/lib/libixml.so.2
@@ -0,0 +1 @@
+/usr/local/lib/libixml.so.2.0.8
\ No newline at end of file
diff --git a/resources/x86_64/lib/libixml.so.2.0.8 b/resources/x86_64/lib/libixml.so.2.0.8
new file mode 100644
index 0000000000000000000000000000000000000000..5421e87e08c14183a2e66624ad9ad57aac81902c
Binary files /dev/null and b/resources/x86_64/lib/libixml.so.2.0.8 differ
diff --git a/resources/x86_64/lib/libmpdclient.so b/resources/x86_64/lib/libmpdclient.so
new file mode 120000
index 0000000000000000000000000000000000000000..090bac5fcd56f09490dc3e416f46d139aa20a2da
--- /dev/null
+++ b/resources/x86_64/lib/libmpdclient.so
@@ -0,0 +1 @@
+/usr/local/lib/libmpdclient.so.2
\ No newline at end of file
diff --git a/resources/x86_64/lib/libmpdclient.so.2 b/resources/x86_64/lib/libmpdclient.so.2
new file mode 120000
index 0000000000000000000000000000000000000000..556f69cac04f6bf8efae6205a516366f1df41035
--- /dev/null
+++ b/resources/x86_64/lib/libmpdclient.so.2
@@ -0,0 +1 @@
+/usr/local/lib/libmpdclient.so.2.14
\ No newline at end of file
diff --git a/resources/x86_64/lib/libmpdclient.so.2.14 b/resources/x86_64/lib/libmpdclient.so.2.14
new file mode 100755
index 0000000000000000000000000000000000000000..aa4b1f4ad3c7827ed78f3a8ab84164aaab128a86
Binary files /dev/null and b/resources/x86_64/lib/libmpdclient.so.2.14 differ
diff --git a/resources/x86_64/lib/libstdc++.so.6 b/resources/x86_64/lib/libstdc++.so.6
new file mode 120000
index 0000000000000000000000000000000000000000..470f7733336c7a57350d085750b61b9032b1b94f
--- /dev/null
+++ b/resources/x86_64/lib/libstdc++.so.6
@@ -0,0 +1 @@
+libstdc++.so.6.0.25
\ No newline at end of file
diff --git a/resources/x86_64/lib/libstdc++.so.6.0.25 b/resources/x86_64/lib/libstdc++.so.6.0.25
new file mode 100644
index 0000000000000000000000000000000000000000..d861fefd736bb84e888fc8012774c37714013cc4
Binary files /dev/null and b/resources/x86_64/lib/libstdc++.so.6.0.25 differ
diff --git a/resources/x86_64/lib/libthreadutil.so b/resources/x86_64/lib/libthreadutil.so
new file mode 120000
index 0000000000000000000000000000000000000000..256d515a2ad25af4ad090811b36341253b9ada12
--- /dev/null
+++ b/resources/x86_64/lib/libthreadutil.so
@@ -0,0 +1 @@
+/usr/local/lib/libthreadutil.so.6.0.4
\ No newline at end of file
diff --git a/resources/x86_64/lib/libthreadutil.so.6 b/resources/x86_64/lib/libthreadutil.so.6
new file mode 120000
index 0000000000000000000000000000000000000000..256d515a2ad25af4ad090811b36341253b9ada12
--- /dev/null
+++ b/resources/x86_64/lib/libthreadutil.so.6
@@ -0,0 +1 @@
+/usr/local/lib/libthreadutil.so.6.0.4
\ No newline at end of file
diff --git a/resources/x86_64/lib/libthreadutil.so.6.0.4 b/resources/x86_64/lib/libthreadutil.so.6.0.4
new file mode 100644
index 0000000000000000000000000000000000000000..914904b9058f85cfaa7bf0919de9d5632c05d6e0
Binary files /dev/null and b/resources/x86_64/lib/libthreadutil.so.6.0.4 differ
diff --git a/resources/x86_64/lib/libupnp.so b/resources/x86_64/lib/libupnp.so
new file mode 120000
index 0000000000000000000000000000000000000000..57f6fee611eb7cff67fe497d04b8884636d90839
--- /dev/null
+++ b/resources/x86_64/lib/libupnp.so
@@ -0,0 +1 @@
+/usr/local/lib/libupnp.so.6.3.3
\ No newline at end of file
diff --git a/resources/x86_64/lib/libupnp.so.6 b/resources/x86_64/lib/libupnp.so.6
new file mode 120000
index 0000000000000000000000000000000000000000..57f6fee611eb7cff67fe497d04b8884636d90839
--- /dev/null
+++ b/resources/x86_64/lib/libupnp.so.6
@@ -0,0 +1 @@
+/usr/local/lib/libupnp.so.6.3.3
\ No newline at end of file
diff --git a/resources/x86_64/lib/libupnp.so.6.3.3 b/resources/x86_64/lib/libupnp.so.6.3.3
new file mode 100644
index 0000000000000000000000000000000000000000..7af5e054eb9e51501a7534dd18ce7d1365adffdd
Binary files /dev/null and b/resources/x86_64/lib/libupnp.so.6.3.3 differ
diff --git a/scripts/API/build_bin.sh b/scripts/API/build_bin.sh
new file mode 100755
index 0000000000000000000000000000000000000000..3369a8bec4a2609502e2682569af280a09773caa
--- /dev/null
+++ b/scripts/API/build_bin.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+source ./scripts/API/common
+
+BUILD_DIR=".rest_build"
+
+echo "* Building Snakeoil RestAPI binary"
+echo -n "  + Version: "
+if [ -z "${VERSION}" ]; then
+  echo "Cannot detect version info. Exiting."
+  exit 1
+else
+  echo "${VERSION}"
+fi
+
+echo "  + Branch: ${BRANCH}"
+echo -n  "  + Compiling... "
+if [ -d ${BUILD_DIR} ]; then
+ rm -rf ${BUILD_DIR}
+fi
+
+cmake -S ./API -B ${BUILD_DIR}/ && cmake --build ${BUILD_DIR}
+
+if [ ${?} -ne 0 ]; then
+  echo "Build fail"
+  exit 1
+else
+  echo "OK"
+fi
+
+echo -n "  + Publishing... "
+mkdir -p "${SNAKEOIL}/rest"
+SIZE_BEG=$(wc -c ${BUILD_DIR}/${BIN}   | awk '{print $1}')
+strip ${BUILD_DIR}/${BIN}
+
+copy ${BUILD_DIR}/${BIN} "$SNAKEOIL/rest"
+
+if [ ! -f "${SNAKEOIL}/rest/${BIN}" ]; then
+  echo "Copy binary fail"
+  exit 1;
+else
+  echo "OK"
+fi
+
+CHECKSUM=$(sha1sum ${BUILD_DIR}/${BIN} | awk '{print $1}')
+SIZE_END=$(wc -c ${BUILD_DIR}/${BIN}   | awk '{print $1}')
+echo "  + Checksum: ${CHECKSUM}"
+echo "  +     Size: ${SIZE_BEG} (${SIZE_END} stripped)"
+echo "* Snakeoil RestAPI binary build complete."
+
+exit 0
+
diff --git a/scripts/API/build_firmware.sh b/scripts/API/build_firmware.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7c3023cf3cc567402beb71eed0bfd2b4cb0bfe1e
--- /dev/null
+++ b/scripts/API/build_firmware.sh
@@ -0,0 +1,128 @@
+#!/bin/bash
+source ./scripts/API/common
+
+echo "* Preparing environment"
+echo -n "  + Checking if snakeoil-rest is built: "
+if [ ! -f "${SNAKEOIL}/rest/${BIN}" ]; then
+  echo "REST not built yet, exiting."
+  echo "${TMP_FW}/rest"
+  exit 1
+else
+  echo "YES"
+fi
+
+echo -n "  + Checking if WebApp is built: "
+if [ ! -d "${SNAKEOIL}/www/" ]; then
+  echo "WWW not build yet, exiting."
+  exit 1
+else
+  echo "YES"
+fi
+
+echo -n "  + Firmware version: "
+if [ -z "${VERSION}" ]; then
+  echo "Cannot detect version info. Exiting."
+  exit 1
+else
+  echo "${VERSION}"
+fi
+
+TMPDIR=$(mktemp -d)
+TMP_FW="${TMPDIR}/www.so_os.www"
+
+REL_FW="binaries/firmware"
+mkdir -p ${REL_FW}
+
+mkdir "${TMP_FW}/bin" -p
+mkdir "${TMP_FW}/etc/default/grub" -p
+mkdir "${TMP_FW}/html" -p
+mkdir "${TMP_FW}/rest" -p
+echo "${ARCH}" > "${TMP_FW}/arch.txt"
+
+echo -n "* Copy misc components... "
+copy "${BUILD_ENV}"/bin/mympd                 "${TMP_FW}/bin"
+copy resources/scripts/alsa_unmute            "${TMP_FW}/bin" 
+copy resources/scripts/mpd_remote.sh          "${TMP_FW}/bin" 
+copy resources/scripts/minimserver_remote.sh  "${TMP_FW}/bin"
+copy resources/grub.template                  "${TMP_FW}/"
+copy resources/mympd.conf                     "${TMP_FW}/"
+copy resources/update_snakeoil.sh             "${TMP_FW}/"
+copy resources/toprc                          "${TMP_FW}/"
+copy "${SNAKEOIL}"/rest/${BIN}                "${TMP_FW}/rest"
+echo "OK"
+
+echo -n "* Copy WebApp... "
+copy "${BUILD_ENV}/snakeoil/${SEMVER}/www/"* ${TMP_FW}/html
+echo "OK"
+
+echo -n "* Music players supported by this firmware ... "
+mkdir -p "${TMP_FW}/html/players"
+copy "${BUILD_ENV}/players/"* "${TMP_FW}/html/players"
+echo "OK"
+for PLAYER in ${TMP_FW}/html/players/*/ ; do
+  if [ -f "${PLAYER}/config" ]; then
+    PLAYER_NAME=$(cat "${PLAYER}/config" |grep PLAYER_NAME|sed 's/.*PLAYER_NAME="\(.*\).*\"/\1/g')
+    echo "  + Player: ${PLAYER_NAME}"
+  else
+    rm -rf "${PLAYER}"
+  fi
+done
+
+echo "* Building upgrade firmware..."
+echo -n "  + Compressing... "
+MSGS=$(cd "${TMPDIR}" && tar -cjf snakeoil-${SEMVER}-${ARCH}.tar.bz2 www.so_os.www)
+errChk
+echo "OK"
+echo -n "  + Encrypting..."
+MSGS=$(snakeoil-encrypt ${TMPDIR}/snakeoil-$SEMVER-$ARCH.tar.bz2 "$REL_FW"/snakeoil-$ARCH-$SEMVER.fw)
+if [ -f "$REL_FW"/snakeoil-$ARCH-$SEMVER.fw ]; then
+  echo "OK"
+else
+  exit 1
+fi
+
+echo -n "  + Copying firmware to Nextcloud... "
+if [ "${BRANCH}" == "master" ]; then
+  copy "$REL_FW"/snakeoil-$ARCH-$SEMVER.fw /storage/releases/Firmware
+  echo "OK"
+else
+  echo "Skipped"
+fi
+
+echo "* Building installer blob..."
+# Installer:
+# Exclude RestAPI server, 
+# Include VNC files
+# Include libs
+# include new_issue script
+# Include system bins
+# Include ALSA sub
+copy "${BUILD_ENV}"/bin/*        "${TMP_FW}/bin"
+copy resources/scripts/new_issue ${TMP_FW}
+copy resources/alsa              ${TMP_FW} -R
+
+mkdir ${TMP_FW}/vnc
+copy resources/vnc/* ${TMP_FW}/vnc/
+
+rm ${TMP_FW}/rest/${BIN}
+rmdir ${TMP_FW}/rest
+
+echo -n "  + Compressing... "
+MSGS=$(cd "${TMPDIR}" && tar -cjf install.blob.tar.bz2 www.so_os.www)
+errChk
+echo "OK"
+echo -n "  + Encrypting..."
+MSGS=$(snakeoil-encrypt ${TMPDIR}/install.blob.tar.bz2 "${SNAKEOIL}"/install.blob)
+if [ -f "${SNAKEOIL}/install.blob" ]; then
+  echo "OK"
+else
+  exit 1
+fi
+
+echo -n "* Cleaning up: ${TMPDIR}... "
+rm -rf "${TMPDIR}"
+echo "OK"
+
+echo "* Done"
+exit 0
+
diff --git a/scripts/API/build_installer.sh b/scripts/API/build_installer.sh
new file mode 100755
index 0000000000000000000000000000000000000000..38feae40b9391194b03aba215f3dcdf1233f6d12
--- /dev/null
+++ b/scripts/API/build_installer.sh
@@ -0,0 +1,206 @@
+#!/usr/bin/env bash 
+source ./scripts/API/common
+
+INSTALL="binaries/installer/snakeoil-installer-${ARCH}-${SEMVER}.sh"
+
+mkdir -p binaries/installer
+
+if [ ! -d "${SNAKEOIL}" ]; then
+  mkdir -p "${SNAKEOIL}"
+fi
+
+BUILD_ARCHIVE="yes"
+TEST_HOST=""
+TEST_USER=""
+
+die() { echo "$*" >&2; exit 2; }  # complain to STDERR and exit with error
+needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }
+
+while getopts sh-: OPT;
+do
+  # support long options: https://stackoverflow.com/a/28466267/519360
+  if [ "$OPT" = "-" ]; then   # long option: reformulate OPT and OPTARG
+    OPT="${OPTARG%%=*}"       # extract long option name
+    OPTARG="${OPTARG#$OPT}"   # extract long option argument (may be empty)
+    OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
+  fi
+  case "$OPT" in
+    h | help )
+              echo -e "Snakeoil Installer Builder ${VERSION}\n"
+              echo "[options]"
+              echo " -h | --help: Show this help"
+              echo " -s | --skip: Skip build archive if one exist (saves time) "
+              echo "    --server: IP of test server to scp installer to"
+              echo "      --user: User name of test server"
+              exit 0
+              ;;
+    s | skip )
+              BUILD_ARCHIVE="no"
+              ;;
+    server)   needs_arg; TEST_HOST="${OPTARG}";;
+    user)     needs_arg; TEST_USER="${OPTARG}";;
+    ??* )     die "Illegal option --$OPT" ;;  # bad long option
+    ? )       exit 2 ;;  # bad short option (error reported via getopts)
+  esac
+done
+
+echo "* Building Installer for ${VERSION}"
+echo -n "  + Checking prequisites... "
+copy ./resources/template/installer.template "${INSTALL}"
+if [ ! -f "${INSTALL}" ]; then
+  echo "Copy of installer script failed"
+  exit 1
+fi
+if [ ! -f "${SNAKEOIL}/rest/${BIN}" ]; then
+  echo "RestAPI binary missing"
+  exit 1
+fi
+
+if [ ! -f "${SNAKEOIL}/install.blob" ]; then
+  echo "Snakeoil blob missing"
+  exit 1
+fi
+
+case "${ARCH}" in
+  "x86_64")
+    LMS_FILE="logitechmediaserver_8.0.1~1606059084_amd64.deb"
+    ;;
+
+  "armv7l")
+    LMS_FILE="logitechmediaserver_8.0.1~1606059084_arm.deb"
+    ;;
+
+  *)
+    echo " ${ARCH} not supported"
+    exit 1
+esac
+
+LMS="/storage/releases/Music Players/Logitech Media Server/${LMS_FILE}"
+
+if [ ! -f "${LMS}" ]; then
+  echo " LMS missing: ${LMS}"
+  exit 1
+fi
+echo "OK"
+
+echo "  + Generating checksums of components"
+echo -n "    - component: ${BIN}... "
+API_SUM=$(sha1sum "${SNAKEOIL}/rest/${BIN}" | awk '{print $1}')
+API_SIZE=$(wc -c  "${SNAKEOIL}/rest/${BIN}" | awk '{print $1}')
+echo "OK"
+echo "      % Size: ${API_SIZE}"
+echo "      % SHA1: ${API_SUM}"
+
+echo -n "    - component: Snakeoil blob... "
+BLOB_SUM=$(sha1sum "${SNAKEOIL}/install.blob" | awk '{print $1}')
+BLOB_SIZE=$(wc -c  "${SNAKEOIL}/install.blob" | awk '{print $1}')
+echo "OK"
+echo "      % Size: ${BLOB_SIZE}"
+echo "      % SHA1: ${BLOB_SUM}"
+
+echo -n "    - component: Logitech Media Server "
+LMS_SUM=$(sha1sum "${LMS}"|awk '{print $1}')
+LMS_SIZE=$(wc -c "${LMS}" |awk '{print $1}')
+echo "OK"
+echo "      % Size: ${LMS_SIZE}"
+echo "      % SHA1: ${LMS_SUM}"
+
+# embed archive
+TMPDIR=$(mktemp -d)
+if [[ ("${BUILD_ARCHIVE}" == "yes") || ((! -f "/tmp/${SEMVER}.archive") && "${BUILD_ARCHIVE}" == "no") ]]; then
+  echo -n "  + Generating archive... "
+  ARCHIVE=$(mktemp)
+  copy "${SNAKEOIL}/rest/${BIN}" "${TMPDIR}"
+  copy "${SNAKEOIL}/install.blob" "${TMPDIR}"
+  copy resources/smb.conf "${TMPDIR}"
+  copy "${LMS}" "${TMPDIR}"
+
+  sudo chown -R root:root ${TMPDIR}/*
+  MSGS=$(cd ${TMPDIR} && tar -cjf ${ARCHIVE} *)
+  if [ ! -f ${ARCHIVE} ]; then
+    echo "Error creating archive: ${MSGS}"
+  else
+    # Calculate the offsets
+    ARC_SIZE=$(wc -c ${ARCHIVE} | awk '{print $1}')
+    ARC_BEG=$(expr `wc -l "${INSTALL}"   | awk '{print $1}'` + 1)
+    ARC_SUM=$(sha1sum "${ARCHIVE}" | awk '{print $1}')
+
+    echo "OK"
+    echo "    - archive: snakeoil.tar.bz2"
+    echo "      % Size: ${ARC_SIZE}"
+    echo "      % SHA1: $ARC_SUM"
+
+    # embed macros
+    echo -n "  + Embedding archive to installer... "
+    sed "${INSTALL}" -i -e "s/@VERSION@/${VERSION}/g" \
+                        -e "s/@ARC_BEG@/${ARC_BEG}/g" \
+                        -e "s/@ARC_SUM@/${ARC_SUM}/g" \
+                        -e "s/@BLOB_SUM@/${BLOB_SUM}/g" \
+                        -e "s/@API_SUM@/${API_SUM}/g" \
+                        -e "s/@LMS_SUM@/${LMS_SUM}/g" \
+                        -e "s/@LMS@/${LMS_FILE}/g"
+
+    if [ "${BUILD_ARCHIVE}" == "no" ]; then
+      copy ${ARCHIVE} /tmp/${SEMVER}.archive
+    fi
+    cat ${ARCHIVE} >> "${INSTALL}"
+    echo "OK"
+  fi
+else
+  if [ ! -f "/tmp/${SEMVER}.archive" ]; then
+    echo "Archive is missing: /tmp/${SEMVER}.archive"
+    exit 1
+  fi
+  echo -n "  + Reusing pre-generated archive... "
+  ARCHIVE="/tmp/${SEMVER}.archive"
+  # Calculate the offsets
+  ARC_SIZE=$(wc -c ${ARCHIVE} | awk '{print $1}')
+  ARC_BEG=$(expr `wc -l "${INSTALL}"   | awk '{print $1}'` + 1)
+  ARC_SUM=$(sha1sum "${ARCHIVE}" | awk '{print $1}')
+  
+  echo "OK"
+  echo "    - archive: snakeoil.tar.bz2"
+  echo "      % Size: ${ARC_SIZE}"
+  echo "      % SHA1: $ARC_SUM"
+  
+  # embed macros
+  echo -n "  + Embedding archive to installer... "
+  sed "${INSTALL}" -i -e "s/@VERSION@/${VERSION}/g" \
+                      -e "s/@ARC_BEG@/${ARC_BEG}/g" \
+                      -e "s/@ARC_SUM@/${ARC_SUM}/g" \
+                      -e "s/@BLOB_SUM@/${BLOB_SUM}/g" \
+                      -e "s/@API_SUM@/${API_SUM}/g" \
+                      -e "s/@LMS_SUM@/${LMS_SUM}/g" \
+                      -e "s/@LMS@/${LMS_FILE}/g"
+  
+  cat ${ARCHIVE} >> "${INSTALL}"
+  echo "OK"
+fi
+
+rm -rf ${TMPDIR}
+if [ "${BUILD_ARCHIVE}" == "yes" ]; then
+  rm -f ${ARCHIVE}
+fi
+
+chmod 755 "${INSTALL}"
+
+if [ -n "${TEST_HOST}" ] && [ -n "${TEST_USER}" ]; then
+  echo -n "  + Copying installer to test VM ($TEST_HOST)... "
+  scp "${INSTALL}" ${TEST_USER}@${TEST_HOST}:/home/${TEST_USER} > /dev/null
+  if [ $? -eq 0 ]; then
+    echo "OK"
+  else
+    exit 1
+  fi
+fi
+echo -n "  + Copying installer to Nextcloud... "
+if [ "${BRANCH}" == "master" ]; then
+  copy ${INSTALL} /storage/releases/Installer/
+  echo "OK"
+else
+  echo "Skipped"
+fi
+echo ""
+echo "* Installer script complete"
+echo ""
+
diff --git a/scripts/API/common b/scripts/API/common
new file mode 100644
index 0000000000000000000000000000000000000000..fa212b786115a9d1cadc44a012b3fc79da189e95
--- /dev/null
+++ b/scripts/API/common
@@ -0,0 +1,32 @@
+#!/bin/bash
+BRANCH=
+if [ -z $CI_COMMIT_REF_NAME ]; then
+  BRANCH=$(git branch |grep \* | sed -e "s/\*\ \(.*\)/\1/g")
+else
+  BRANCH=$CI_COMMIT_REF_NAME
+fi
+
+if [ -z "${BRANCH}" ]; then
+  echo "Cannot detect branch name. Exiting."
+  exit 1
+fi
+
+VERSION=$(cat API/CMakeLists.txt| grep _api | sed -e "s/.* \(.*\))/\1/g")
+SEMVER=$(echo $VERSION|awk '{print $1}')
+ARCH=$(uname -m)
+BUILD_ENV="/storage/artifacts/${ARCH}"
+SNAKEOIL="${BUILD_ENV}/snakeoil/${SEMVER}"
+BIN="snakeoil-rest"
+
+function errChk() {
+  if [ ${?} -ne 0 ]; then
+    echo "Error"
+    exit 1
+  fi
+}
+
+function copy() {
+  cp "${@}" -rf
+  errChk
+}
+
diff --git a/scripts/API/snakeoil-rest b/scripts/API/snakeoil-rest
new file mode 100644
index 0000000000000000000000000000000000000000..2ba811529af98f2678d94233a10825cadc88504f
--- /dev/null
+++ b/scripts/API/snakeoil-rest
@@ -0,0 +1,114 @@
+#!/bin/sh
+#
+# $Id$
+#
+# snakeoil-rest 	initscript for snakeoil-rest
+#			This file should be placed in /etc/init.d.
+#
+# Original Author: Mattias Holmlund
+#
+# Updated By: Agent Kith
+
+#
+### BEGIN INIT INFO
+# Provides:          	snakeoil-rest
+# Required-Start:    	$all
+# Required-Stop:     	$all
+# Should-Start:      	$all
+# Should-Stop:       	$all
+# Default-Start:     	2 3 4 5
+# Default-Stop:      	0 1 6
+# Short-Description:	Startup script for the snakeoil-rest
+# Description:		Snakeoil REST server.
+### END INIT INFO
+#
+
+set -e
+. /lib/lsb/init-functions
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DESC="snakeoil REST Server"
+NAME=snakeoil-rest
+NEWNAME=snakeoil-rest
+DAEMON=/usr/local/sbin/$NAME
+PIDFILE=/var/run/$NEWNAME.pid
+SCRIPTNAME=/etc/init.d/$NEWNAME
+PREFSDIR=/var/www/html/config
+LOGDIR=/var/log/$NAME/
+SNAKEOIL_USER=root
+CHARSET=utf8
+
+## if you want to add additional options
+## use /usr/sbin/squeezeboxserver --help 
+## for the supported options and place them
+## into the configfile  /etc/default/snakeoil-rest
+
+
+# Read config file if it is present.
+if [ -r /etc/default/$NEWNAME ]; then
+	. /etc/default/$NEWNAME
+elif [ -r /etc/default/$NAME ]; then
+	. /etc/default/$NAME
+fi
+
+#
+#	Function that starts the daemon/service.
+#
+d_start() {
+        # Use squeezeboxserver_safe to restart the daemon when
+        # it dies. This must be done to handle mysql restarts.
+	start-stop-daemon --start --quiet \
+                --chuid $SNAKEOIL_USER \
+                --pidfile $PIDFILE \
+		--exec $DAEMON
+}
+
+#	Function that stops the daemon/service.
+#
+d_stop() {
+
+	## This is a bug in the start-stop-daemon that checks the PID name from the /proc/PID/stat filesystem...
+	## Unfortunately this cuts-off the name of the daemon because its longer now, and then it doesnt get 
+	## caught by the start-stop-daemon. The daemon actually reports it as squeezeboxserve instead of 
+	## squeezeboxserver_safe.
+	start-stop-daemon --oknodo --stop --pidfile $PIDFILE --retry=TERM/30/KILL/5
+}
+
+#
+#	Function that sends a SIGHUP to the daemon/service.
+#
+
+case "$1" in
+  start)
+	echo -n "Making sure that $DESC is not running first: "
+	d_stop
+	echo -n "Starting $DESC"
+	d_start
+	echo "."
+	;;
+  stop)
+	echo -n "Stopping $DESC"
+	d_stop
+	echo "."
+	;;
+  restart|force-reload)
+	#
+	#	If the "reload" option is implemented, move the "force-reload"
+	#	option to the "reload" entry above. If not, "force-reload" is
+	#	just the same as "restart".
+	#
+	echo -n "Restarting $NAME"
+	d_stop
+	d_start
+	echo "."
+	;;
+  status)  
+	status_of_proc /usr/bin/$NEWNAME $NEWNAME
+	;;
+  *)
+	echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2
+	exit 1
+	;;
+esac
+
+exit 0