commit d8a602294706f4d98704a2e1398e4eca66559ba5 Author: Robin Davies Date: Sun Aug 15 12:42:46 2021 -0400 First commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4b58a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +#build files +build/ + +#settings +.vscode + +Testing/ + diff --git a/CMakeCache.txt b/CMakeCache.txt new file mode 100644 index 0000000..40bce9d --- /dev/null +++ b/CMakeCache.txt @@ -0,0 +1,547 @@ +# This is the CMakeCache file. +# For build in directory: /home/patch/src/piddle +# It was generated by CMake: /usr/local/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 +######################## + +//Build the testing tree. +BUILD_TESTING:BOOL=ON + +//Path to a program. +BZRCOMMAND:FILEPATH=BZRCOMMAND-NOTFOUND + +//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-8 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-8 + +//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-8 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-8 + +//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= + +//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=PiddleTest + +//Value Computed by CMake +CMAKE_PROJECT_VERSION:STATIC=0.1.0 + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_MAJOR:STATIC=0 + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_MINOR:STATIC=1 + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_PATCH:STATIC=0 + +//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 + +//Path to the coverage program that CTest uses for performing coverage +// inspection +COVERAGE_COMMAND:FILEPATH=/usr/bin/gcov + +//Extra command line flags to pass to the coverage tool +COVERAGE_EXTRA_FLAGS:STRING=-l + +//How many times to retry timed-out CTest submissions. +CTEST_SUBMIT_RETRY_COUNT:STRING=3 + +//How long to wait between timed-out CTest submissions. +CTEST_SUBMIT_RETRY_DELAY:STRING=5 + +//Path to a program. +CVSCOMMAND:FILEPATH=/usr/bin/cvs + +//Options passed to the cvs update command. +CVS_UPDATE_OPTIONS:STRING=-d -A -P + +//Maximum time allowed before CTest will kill the test. +DART_TESTING_TIMEOUT:STRING=1500 + +//Path to a program. +GITCOMMAND:FILEPATH=/usr/bin/git + +//Path to a program. +HGCOMMAND:FILEPATH=/usr/bin/hg + +//Command to build the project +MAKECOMMAND:STRING=/usr/local/bin/cmake --build . --config "${CTEST_CONFIGURATION_TYPE}" + +//Path to the memory checking command, used for memory error detection. +MEMORYCHECK_COMMAND:FILEPATH=MEMORYCHECK_COMMAND-NOTFOUND + +//File that contains suppressions for the memory checker +MEMORYCHECK_SUPPRESSIONS_FILE:FILEPATH= + +//Path to a program. +P4COMMAND:FILEPATH=P4COMMAND-NOTFOUND + +//pkg-config executable +PKG_CONFIG_EXECUTABLE:FILEPATH=/usr/bin/pkg-config + +//Value Computed by CMake +PiddleTest_BINARY_DIR:STATIC=/home/patch/src/piddle + +//Value Computed by CMake +PiddleTest_SOURCE_DIR:STATIC=/home/patch/src/piddle/test + +//Name of the computer/site where compile is being run +SITE:STRING=patchbox + +//Path to the SLURM sbatch executable +SLURM_SBATCH_COMMAND:FILEPATH=SLURM_SBATCH_COMMAND-NOTFOUND + +//Path to the SLURM srun executable +SLURM_SRUN_COMMAND:FILEPATH=SLURM_SRUN_COMMAND-NOTFOUND + +//Path to a program. +SVNCOMMAND:FILEPATH=/usr/bin/svn + +//Path to a library. +pkgcfg_lib_LILV_0_dl:FILEPATH=/usr/lib/arm-linux-gnueabihf/libdl.so + +//Path to a library. +pkgcfg_lib_LILV_0_lilv-0:FILEPATH=/usr/lib/arm-linux-gnueabihf/liblilv-0.so + +//Path to a library. +pkgcfg_lib_LILV_0_serd-0:FILEPATH=/usr/lib/arm-linux-gnueabihf/libserd-0.so + +//Path to a library. +pkgcfg_lib_LILV_0_sord-0:FILEPATH=/usr/lib/arm-linux-gnueabihf/libsord-0.so + +//Path to a library. +pkgcfg_lib_LILV_0_sratom-0:FILEPATH=/usr/lib/arm-linux-gnueabihf/libsratom-0.so + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: BZRCOMMAND +BZRCOMMAND-ADVANCED:INTERNAL=1 +//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/patch/src/piddle +//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=19 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=4268486 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/local/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/local/bin/cpack +//ADVANCED property for variable: CMAKE_CTEST_COMMAND +CMAKE_CTEST_COMMAND-ADVANCED:INTERNAL=1 +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/local/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/patch/src/piddle/test +//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/local/share/cmake-3.19 +//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=/usr/bin/uname +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: COVERAGE_COMMAND +COVERAGE_COMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: COVERAGE_EXTRA_FLAGS +COVERAGE_EXTRA_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CTEST_SUBMIT_RETRY_COUNT +CTEST_SUBMIT_RETRY_COUNT-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CTEST_SUBMIT_RETRY_DELAY +CTEST_SUBMIT_RETRY_DELAY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CVSCOMMAND +CVSCOMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CVS_UPDATE_OPTIONS +CVS_UPDATE_OPTIONS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: DART_TESTING_TIMEOUT +DART_TESTING_TIMEOUT-ADVANCED:INTERNAL=1 +//Details about finding PkgConfig +FIND_PACKAGE_MESSAGE_DETAILS_PkgConfig:INTERNAL=[/usr/bin/pkg-config][v0.29()] +//ADVANCED property for variable: GITCOMMAND +GITCOMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: HGCOMMAND +HGCOMMAND-ADVANCED:INTERNAL=1 +LILV_0_CFLAGS:INTERNAL=-I/usr/local/include;-I/usr/include/lilv-0;-I/usr/include/sratom-0;-I/usr/include/sord-0;-I/usr/include/serd-0 +LILV_0_CFLAGS_I:INTERNAL= +LILV_0_CFLAGS_OTHER:INTERNAL= +LILV_0_FOUND:INTERNAL=1 +LILV_0_INCLUDEDIR:INTERNAL=/usr/include +LILV_0_INCLUDE_DIRS:INTERNAL=/usr/local/include;/usr/include/lilv-0;/usr/include/sratom-0;/usr/include/sord-0;/usr/include/serd-0 +LILV_0_LDFLAGS:INTERNAL=-llilv-0;-ldl;-lsratom-0;-lsord-0;-lserd-0 +LILV_0_LDFLAGS_OTHER:INTERNAL= +LILV_0_LIBDIR:INTERNAL=/usr/lib/arm-linux-gnueabihf +LILV_0_LIBRARIES:INTERNAL=lilv-0;dl;sratom-0;sord-0;serd-0 +LILV_0_LIBRARY_DIRS:INTERNAL= +LILV_0_LIBS:INTERNAL= +LILV_0_LIBS_L:INTERNAL= +LILV_0_LIBS_OTHER:INTERNAL= +LILV_0_LIBS_PATHS:INTERNAL= +LILV_0_MODULE_NAME:INTERNAL=lilv-0 +LILV_0_PREFIX:INTERNAL=/usr +LILV_0_STATIC_CFLAGS:INTERNAL=-I/usr/local/include;-I/usr/include/lilv-0;-I/usr/include/sratom-0;-I/usr/include/sord-0;-I/usr/include/serd-0 +LILV_0_STATIC_CFLAGS_I:INTERNAL= +LILV_0_STATIC_CFLAGS_OTHER:INTERNAL= +LILV_0_STATIC_INCLUDE_DIRS:INTERNAL=/usr/local/include;/usr/include/lilv-0;/usr/include/sratom-0;/usr/include/sord-0;/usr/include/serd-0 +LILV_0_STATIC_LDFLAGS:INTERNAL=-llilv-0;-ldl;-lsratom-0;-lsord-0;-lserd-0;-lm +LILV_0_STATIC_LDFLAGS_OTHER:INTERNAL= +LILV_0_STATIC_LIBDIR:INTERNAL= +LILV_0_STATIC_LIBRARIES:INTERNAL=lilv-0;dl;sratom-0;sord-0;serd-0;m +LILV_0_STATIC_LIBRARY_DIRS:INTERNAL= +LILV_0_STATIC_LIBS:INTERNAL= +LILV_0_STATIC_LIBS_L:INTERNAL= +LILV_0_STATIC_LIBS_OTHER:INTERNAL= +LILV_0_STATIC_LIBS_PATHS:INTERNAL= +LILV_0_VERSION:INTERNAL=0.24.2 +LILV_0_lilv-0_INCLUDEDIR:INTERNAL= +LILV_0_lilv-0_LIBDIR:INTERNAL= +LILV_0_lilv-0_PREFIX:INTERNAL= +LILV_0_lilv-0_VERSION:INTERNAL= +//ADVANCED property for variable: MAKECOMMAND +MAKECOMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: MEMORYCHECK_COMMAND +MEMORYCHECK_COMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: MEMORYCHECK_SUPPRESSIONS_FILE +MEMORYCHECK_SUPPRESSIONS_FILE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: P4COMMAND +P4COMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: PKG_CONFIG_EXECUTABLE +PKG_CONFIG_EXECUTABLE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: SITE +SITE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: SLURM_SBATCH_COMMAND +SLURM_SBATCH_COMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: SLURM_SRUN_COMMAND +SLURM_SRUN_COMMAND-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: SVNCOMMAND +SVNCOMMAND-ADVANCED:INTERNAL=1 +__pkg_config_arguments_LILV_0:INTERNAL=lilv-0 +__pkg_config_checked_LILV_0:INTERNAL=1 +//ADVANCED property for variable: pkgcfg_lib_LILV_0_dl +pkgcfg_lib_LILV_0_dl-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: pkgcfg_lib_LILV_0_lilv-0 +pkgcfg_lib_LILV_0_lilv-0-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: pkgcfg_lib_LILV_0_serd-0 +pkgcfg_lib_LILV_0_serd-0-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: pkgcfg_lib_LILV_0_sord-0 +pkgcfg_lib_LILV_0_sord-0-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: pkgcfg_lib_LILV_0_sratom-0 +pkgcfg_lib_LILV_0_sratom-0-ADVANCED:INTERNAL=1 +prefix_result:INTERNAL=/usr/lib/arm-linux-gnueabihf + diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CMakeCCompiler.cmake b/CMakeFiles/3.19.4268486-MSVC_2/CMakeCCompiler.cmake new file mode 100644 index 0000000..7f4f06e --- /dev/null +++ b/CMakeFiles/3.19.4268486-MSVC_2/CMakeCCompiler.cmake @@ -0,0 +1,77 @@ +set(CMAKE_C_COMPILER "/usr/bin/cc") +set(CMAKE_C_COMPILER_ARG1 "") +set(CMAKE_C_COMPILER_ID "GNU") +set(CMAKE_C_COMPILER_VERSION "8.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-8") +set(CMAKE_RANLIB "/usr/bin/ranlib") +set(CMAKE_C_COMPILER_RANLIB "/usr/bin/gcc-ranlib-8") +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 "4") +set(CMAKE_C_COMPILER_ABI "ELF") +set(CMAKE_C_LIBRARY_ARCHITECTURE "arm-linux-gnueabihf") + +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 "arm-linux-gnueabihf") +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/arm-linux-gnueabihf/8/include;/usr/local/include;/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed;/usr/include/arm-linux-gnueabihf;/usr/include") +set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;gcc_s;c;gcc;gcc_s") +set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/arm-linux-gnueabihf/8;/usr/lib/arm-linux-gnueabihf;/usr/lib;/lib/arm-linux-gnueabihf") +set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CMakeCXXCompiler.cmake b/CMakeFiles/3.19.4268486-MSVC_2/CMakeCXXCompiler.cmake new file mode 100644 index 0000000..47cc89a --- /dev/null +++ b/CMakeFiles/3.19.4268486-MSVC_2/CMakeCXXCompiler.cmake @@ -0,0 +1,89 @@ +set(CMAKE_CXX_COMPILER "/usr/bin/c++") +set(CMAKE_CXX_COMPILER_ARG1 "") +set(CMAKE_CXX_COMPILER_ID "GNU") +set(CMAKE_CXX_COMPILER_VERSION "8.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-8") +set(CMAKE_RANLIB "/usr/bin/ranlib") +set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/gcc-ranlib-8") +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 "4") +set(CMAKE_CXX_COMPILER_ABI "ELF") +set(CMAKE_CXX_LIBRARY_ARCHITECTURE "arm-linux-gnueabihf") + +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 "arm-linux-gnueabihf") +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++/8;/usr/include/arm-linux-gnueabihf/c++/8;/usr/include/c++/8/backward;/usr/lib/gcc/arm-linux-gnueabihf/8/include;/usr/local/include;/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed;/usr/include/arm-linux-gnueabihf;/usr/include") +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;m;gcc_s;gcc;c;gcc_s;gcc") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/arm-linux-gnueabihf/8;/usr/lib/arm-linux-gnueabihf;/usr/lib;/lib/arm-linux-gnueabihf") +set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CMakeDetermineCompilerABI_C.bin b/CMakeFiles/3.19.4268486-MSVC_2/CMakeDetermineCompilerABI_C.bin new file mode 100755 index 0000000..d426f58 Binary files /dev/null and b/CMakeFiles/3.19.4268486-MSVC_2/CMakeDetermineCompilerABI_C.bin differ diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CMakeDetermineCompilerABI_CXX.bin b/CMakeFiles/3.19.4268486-MSVC_2/CMakeDetermineCompilerABI_CXX.bin new file mode 100755 index 0000000..c68e206 Binary files /dev/null and b/CMakeFiles/3.19.4268486-MSVC_2/CMakeDetermineCompilerABI_CXX.bin differ diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CMakeSystem.cmake b/CMakeFiles/3.19.4268486-MSVC_2/CMakeSystem.cmake new file mode 100644 index 0000000..c41c419 --- /dev/null +++ b/CMakeFiles/3.19.4268486-MSVC_2/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Linux-5.10.17-v7l+") +set(CMAKE_HOST_SYSTEM_NAME "Linux") +set(CMAKE_HOST_SYSTEM_VERSION "5.10.17-v7l+") +set(CMAKE_HOST_SYSTEM_PROCESSOR "armv7l") + + + +set(CMAKE_SYSTEM "Linux-5.10.17-v7l+") +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_VERSION "5.10.17-v7l+") +set(CMAKE_SYSTEM_PROCESSOR "armv7l") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdC/CMakeCCompilerId.c b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdC/CMakeCCompilerId.c new file mode 100644 index 0000000..b532cf7 --- /dev/null +++ b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdC/CMakeCCompilerId.c @@ -0,0 +1,721 @@ +#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__) && defined(__INTEL_DPCPP_COMPILER__) +# define COMPILER_ID "IntelDPCPP" +# 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(__INTEL_DPCPP_COMPILER__) + +#elif defined(__clang__) && defined(__INTEL_CLANG_COMPILER) +# define COMPILER_ID "IntelClang" +# 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(__INTEL_CLANG_COMPILER) + +#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" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# 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 + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# 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/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdC/a.out b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdC/a.out new file mode 100755 index 0000000..acbddc9 Binary files /dev/null and b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdC/a.out differ diff --git a/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 0000000..63067f5 --- /dev/null +++ b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,710 @@ +/* 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__) && defined(__INTEL_DPCPP_COMPILER__) +# define COMPILER_ID "IntelDPCPP" +# 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(__INTEL_DPCPP_COMPILER__) + +#elif defined(__clang__) && defined(__INTEL_CLANG_COMPILER) +# define COMPILER_ID "IntelClang" +# 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(__INTEL_CLANG_COMPILER) + +#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" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# 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 + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# 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/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/a.out b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/a.out new file mode 100755 index 0000000..9da3dfc Binary files /dev/null and b/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/a.out differ diff --git a/CMakeFiles/CMakeOutput.log b/CMakeFiles/CMakeOutput.log new file mode 100644 index 0000000..43df68d --- /dev/null +++ b/CMakeFiles/CMakeOutput.log @@ -0,0 +1,403 @@ +The system is: Linux - 5.10.17-v7l+ - armv7l +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/patch/src/piddle/CMakeFiles/3.19.4268486-MSVC_2/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/patch/src/piddle/CMakeFiles/3.19.4268486-MSVC_2/CompilerIdCXX/a.out" + +Detecting C compiler ABI info compiled with the following output: +Change Dir: /home/patch/src/piddle/CMakeFiles/CMakeTmp + +Run Build Command(s):/usr/bin/make cmTC_ccc35/fast && /usr/bin/make -f CMakeFiles/cmTC_ccc35.dir/build.make CMakeFiles/cmTC_ccc35.dir/build +make[1]: Entering directory '/home/patch/src/piddle/CMakeFiles/CMakeTmp' +Building C object CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o +/usr/bin/cc -v -o CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -c /usr/local/share/cmake-3.19/Modules/CMakeCCompilerABI.c +Using built-in specs. +COLLECT_GCC=/usr/bin/cc +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o' '-c' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' + /usr/lib/gcc/arm-linux-gnueabihf/8/cc1 -quiet -v -imultilib . -imultiarch arm-linux-gnueabihf /usr/local/share/cmake-3.19/Modules/CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mfloat-abi=hard -mfpu=vfp -mtls-dialect=gnu -marm -march=armv6+fp -auxbase-strip CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -version -o /tmp/ccSVpxtc.s +GNU C17 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf) + compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +ignoring nonexistent directory "/usr/local/include/arm-linux-gnueabihf" +ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/8/../../../../arm-linux-gnueabihf/include" +#include "..." search starts here: +#include <...> search starts here: + /usr/lib/gcc/arm-linux-gnueabihf/8/include + /usr/local/include + /usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed + /usr/include/arm-linux-gnueabihf + /usr/include +End of search list. +GNU C17 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf) + compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +Compiler executable checksum: bcc8c085e8c103b65550a3bb7c44a354 +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o' '-c' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' + as -v -march=armv6 -mfloat-abi=hard -mfpu=vfp -meabi=5 -o CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o /tmp/ccSVpxtc.s +GNU assembler version 2.31.1 (arm-linux-gnueabihf) using BFD version (GNU Binutils for Raspbian) 2.31.1 +COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/ +LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/ +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o' '-c' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' +Linking C executable cmTC_ccc35 +/usr/local/bin/cmake -E cmake_link_script CMakeFiles/cmTC_ccc35.dir/link.txt --verbose=1 +/usr/bin/cc -v CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -o cmTC_ccc35 +Using built-in specs. +COLLECT_GCC=/usr/bin/cc +COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) +COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/ +LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_ccc35' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' + /usr/lib/gcc/arm-linux-gnueabihf/8/collect2 -plugin /usr/lib/gcc/arm-linux-gnueabihf/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper -plugin-opt=-fresolution=/tmp/cc0QNZ8j.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu -m armelf_linux_eabi -o cmTC_ccc35 /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/8 -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../.. -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crtn.o +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_ccc35' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' +make[1]: Leaving directory '/home/patch/src/piddle/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/arm-linux-gnueabihf/8/include] + add: [/usr/local/include] + add: [/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] + add: [/usr/include/arm-linux-gnueabihf] + add: [/usr/include] + end of search list found + collapse include dir [/usr/lib/gcc/arm-linux-gnueabihf/8/include] ==> [/usr/lib/gcc/arm-linux-gnueabihf/8/include] + collapse include dir [/usr/local/include] ==> [/usr/local/include] + collapse include dir [/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] ==> [/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] + collapse include dir [/usr/include/arm-linux-gnueabihf] ==> [/usr/include/arm-linux-gnueabihf] + collapse include dir [/usr/include] ==> [/usr/include] + implicit include dirs: [/usr/lib/gcc/arm-linux-gnueabihf/8/include;/usr/local/include;/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed;/usr/include/arm-linux-gnueabihf;/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/patch/src/piddle/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command(s):/usr/bin/make cmTC_ccc35/fast && /usr/bin/make -f CMakeFiles/cmTC_ccc35.dir/build.make CMakeFiles/cmTC_ccc35.dir/build] + ignore line: [make[1]: Entering directory '/home/patch/src/piddle/CMakeFiles/CMakeTmp'] + ignore line: [Building C object CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o] + ignore line: [/usr/bin/cc -v -o CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -c /usr/local/share/cmake-3.19/Modules/CMakeCCompilerABI.c] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/cc] + ignore line: [Target: arm-linux-gnueabihf] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o' '-c' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + ignore line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/cc1 -quiet -v -imultilib . -imultiarch arm-linux-gnueabihf /usr/local/share/cmake-3.19/Modules/CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mfloat-abi=hard -mfpu=vfp -mtls-dialect=gnu -marm -march=armv6+fp -auxbase-strip CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -version -o /tmp/ccSVpxtc.s] + ignore line: [GNU C17 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf)] + ignore line: [ compiled by GNU C version 8.3.0 GMP version 6.1.2 MPFR version 4.0.2 MPC version 1.1.0 isl version isl-0.20-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/arm-linux-gnueabihf"] + ignore line: [ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/8/../../../../arm-linux-gnueabihf/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/include] + ignore line: [ /usr/local/include] + ignore line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] + ignore line: [ /usr/include/arm-linux-gnueabihf] + ignore line: [ /usr/include] + ignore line: [End of search list.] + ignore line: [GNU C17 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf)] + ignore line: [ compiled by GNU C version 8.3.0 GMP version 6.1.2 MPFR version 4.0.2 MPC version 1.1.0 isl version isl-0.20-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [Compiler executable checksum: bcc8c085e8c103b65550a3bb7c44a354] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o' '-c' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + ignore line: [ as -v -march=armv6 -mfloat-abi=hard -mfpu=vfp -meabi=5 -o CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o /tmp/ccSVpxtc.s] + ignore line: [GNU assembler version 2.31.1 (arm-linux-gnueabihf) using BFD version (GNU Binutils for Raspbian) 2.31.1] + ignore line: [COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o' '-c' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + ignore line: [Linking C executable cmTC_ccc35] + ignore line: [/usr/local/bin/cmake -E cmake_link_script CMakeFiles/cmTC_ccc35.dir/link.txt --verbose=1] + ignore line: [/usr/bin/cc -v CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -o cmTC_ccc35 ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/cc] + ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper] + ignore line: [Target: arm-linux-gnueabihf] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) ] + ignore line: [COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_ccc35' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + link line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/collect2 -plugin /usr/lib/gcc/arm-linux-gnueabihf/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper -plugin-opt=-fresolution=/tmp/cc0QNZ8j.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu -m armelf_linux_eabi -o cmTC_ccc35 /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/8 -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../.. -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crtn.o] + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/collect2] ==> ignore + arg [-plugin] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/liblto_plugin.so] ==> ignore + arg [-plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper] ==> ignore + arg [-plugin-opt=-fresolution=/tmp/cc0QNZ8j.res] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [--build-id] ==> ignore + arg [--eh-frame-hdr] ==> ignore + arg [-dynamic-linker] ==> ignore + arg [/lib/ld-linux-armhf.so.3] ==> ignore + arg [-X] ==> ignore + arg [--hash-style=gnu] ==> ignore + arg [-m] ==> ignore + arg [armelf_linux_eabi] ==> ignore + arg [-o] ==> ignore + arg [cmTC_ccc35] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crt1.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crti.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o] ==> ignore + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/8] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/8] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/8/../../..] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../..] + arg [-L/lib/arm-linux-gnueabihf] ==> dir [/lib/arm-linux-gnueabihf] + arg [-L/usr/lib/arm-linux-gnueabihf] ==> dir [/usr/lib/arm-linux-gnueabihf] + arg [CMakeFiles/cmTC_ccc35.dir/CMakeCCompilerABI.c.o] ==> ignore + arg [-lgcc] ==> lib [gcc] + arg [--push-state] ==> ignore + arg [--as-needed] ==> ignore + arg [-lgcc_s] ==> lib [gcc_s] + arg [--pop-state] ==> ignore + arg [-lc] ==> lib [c] + arg [-lgcc] ==> lib [gcc] + arg [--push-state] ==> ignore + arg [--as-needed] ==> ignore + arg [-lgcc_s] ==> lib [gcc_s] + arg [--pop-state] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crtn.o] ==> ignore + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/8] ==> [/usr/lib/gcc/arm-linux-gnueabihf/8] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../..] ==> [/usr/lib] + collapse library dir [/lib/arm-linux-gnueabihf] ==> [/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + implicit libs: [gcc;gcc_s;c;gcc;gcc_s] + implicit dirs: [/usr/lib/gcc/arm-linux-gnueabihf/8;/usr/lib/arm-linux-gnueabihf;/usr/lib;/lib/arm-linux-gnueabihf] + implicit fwks: [] + + +Detecting CXX compiler ABI info compiled with the following output: +Change Dir: /home/patch/src/piddle/CMakeFiles/CMakeTmp + +Run Build Command(s):/usr/bin/make cmTC_67965/fast && /usr/bin/make -f CMakeFiles/cmTC_67965.dir/build.make CMakeFiles/cmTC_67965.dir/build +make[1]: Entering directory '/home/patch/src/piddle/CMakeFiles/CMakeTmp' +Building CXX object CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o +/usr/bin/c++ -v -o CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -c /usr/local/share/cmake-3.19/Modules/CMakeCXXCompilerABI.cpp +Using built-in specs. +COLLECT_GCC=/usr/bin/c++ +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' + /usr/lib/gcc/arm-linux-gnueabihf/8/cc1plus -quiet -v -imultilib . -imultiarch arm-linux-gnueabihf -D_GNU_SOURCE /usr/local/share/cmake-3.19/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mfloat-abi=hard -mfpu=vfp -mtls-dialect=gnu -marm -march=armv6+fp -auxbase-strip CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -version -o /tmp/ccMaJDam.s +GNU C++14 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf) + compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +ignoring duplicate directory "/usr/include/arm-linux-gnueabihf/c++/8" +ignoring nonexistent directory "/usr/local/include/arm-linux-gnueabihf" +ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/8/../../../../arm-linux-gnueabihf/include" +#include "..." search starts here: +#include <...> search starts here: + /usr/include/c++/8 + /usr/include/arm-linux-gnueabihf/c++/8 + /usr/include/c++/8/backward + /usr/lib/gcc/arm-linux-gnueabihf/8/include + /usr/local/include + /usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed + /usr/include/arm-linux-gnueabihf + /usr/include +End of search list. +GNU C++14 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf) + compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +Compiler executable checksum: 7defdc925cf5fede452fc531d54623d1 +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' + as -v -march=armv6 -mfloat-abi=hard -mfpu=vfp -meabi=5 -o CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccMaJDam.s +GNU assembler version 2.31.1 (arm-linux-gnueabihf) using BFD version (GNU Binutils for Raspbian) 2.31.1 +COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/ +LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/ +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' +Linking CXX executable cmTC_67965 +/usr/local/bin/cmake -E cmake_link_script CMakeFiles/cmTC_67965.dir/link.txt --verbose=1 +/usr/bin/c++ -v CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_67965 +Using built-in specs. +COLLECT_GCC=/usr/bin/c++ +COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) +COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/ +LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_67965' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' + /usr/lib/gcc/arm-linux-gnueabihf/8/collect2 -plugin /usr/lib/gcc/arm-linux-gnueabihf/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper -plugin-opt=-fresolution=/tmp/ccUdAo9s.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu -m armelf_linux_eabi -o cmTC_67965 /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/8 -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../.. -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crtn.o +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_67965' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp' +make[1]: Leaving directory '/home/patch/src/piddle/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++/8] + add: [/usr/include/arm-linux-gnueabihf/c++/8] + add: [/usr/include/c++/8/backward] + add: [/usr/lib/gcc/arm-linux-gnueabihf/8/include] + add: [/usr/local/include] + add: [/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] + add: [/usr/include/arm-linux-gnueabihf] + add: [/usr/include] + end of search list found + collapse include dir [/usr/include/c++/8] ==> [/usr/include/c++/8] + collapse include dir [/usr/include/arm-linux-gnueabihf/c++/8] ==> [/usr/include/arm-linux-gnueabihf/c++/8] + collapse include dir [/usr/include/c++/8/backward] ==> [/usr/include/c++/8/backward] + collapse include dir [/usr/lib/gcc/arm-linux-gnueabihf/8/include] ==> [/usr/lib/gcc/arm-linux-gnueabihf/8/include] + collapse include dir [/usr/local/include] ==> [/usr/local/include] + collapse include dir [/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] ==> [/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] + collapse include dir [/usr/include/arm-linux-gnueabihf] ==> [/usr/include/arm-linux-gnueabihf] + collapse include dir [/usr/include] ==> [/usr/include] + implicit include dirs: [/usr/include/c++/8;/usr/include/arm-linux-gnueabihf/c++/8;/usr/include/c++/8/backward;/usr/lib/gcc/arm-linux-gnueabihf/8/include;/usr/local/include;/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed;/usr/include/arm-linux-gnueabihf;/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/patch/src/piddle/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command(s):/usr/bin/make cmTC_67965/fast && /usr/bin/make -f CMakeFiles/cmTC_67965.dir/build.make CMakeFiles/cmTC_67965.dir/build] + ignore line: [make[1]: Entering directory '/home/patch/src/piddle/CMakeFiles/CMakeTmp'] + ignore line: [Building CXX object CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o] + ignore line: [/usr/bin/c++ -v -o CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -c /usr/local/share/cmake-3.19/Modules/CMakeCXXCompilerABI.cpp] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/c++] + ignore line: [Target: arm-linux-gnueabihf] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + ignore line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/cc1plus -quiet -v -imultilib . -imultiarch arm-linux-gnueabihf -D_GNU_SOURCE /usr/local/share/cmake-3.19/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mfloat-abi=hard -mfpu=vfp -mtls-dialect=gnu -marm -march=armv6+fp -auxbase-strip CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -version -o /tmp/ccMaJDam.s] + ignore line: [GNU C++14 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf)] + ignore line: [ compiled by GNU C version 8.3.0 GMP version 6.1.2 MPFR version 4.0.2 MPC version 1.1.0 isl version isl-0.20-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [ignoring duplicate directory "/usr/include/arm-linux-gnueabihf/c++/8"] + ignore line: [ignoring nonexistent directory "/usr/local/include/arm-linux-gnueabihf"] + ignore line: [ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/8/../../../../arm-linux-gnueabihf/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ /usr/include/c++/8] + ignore line: [ /usr/include/arm-linux-gnueabihf/c++/8] + ignore line: [ /usr/include/c++/8/backward] + ignore line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/include] + ignore line: [ /usr/local/include] + ignore line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed] + ignore line: [ /usr/include/arm-linux-gnueabihf] + ignore line: [ /usr/include] + ignore line: [End of search list.] + ignore line: [GNU C++14 (Raspbian 8.3.0-6+rpi1) version 8.3.0 (arm-linux-gnueabihf)] + ignore line: [ compiled by GNU C version 8.3.0 GMP version 6.1.2 MPFR version 4.0.2 MPC version 1.1.0 isl version isl-0.20-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [Compiler executable checksum: 7defdc925cf5fede452fc531d54623d1] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + ignore line: [ as -v -march=armv6 -mfloat-abi=hard -mfpu=vfp -meabi=5 -o CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccMaJDam.s] + ignore line: [GNU assembler version 2.31.1 (arm-linux-gnueabihf) using BFD version (GNU Binutils for Raspbian) 2.31.1] + ignore line: [COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + ignore line: [Linking CXX executable cmTC_67965] + ignore line: [/usr/local/bin/cmake -E cmake_link_script CMakeFiles/cmTC_67965.dir/link.txt --verbose=1] + ignore line: [/usr/bin/c++ -v CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_67965 ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/c++] + ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper] + ignore line: [Target: arm-linux-gnueabihf] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Raspbian 8.3.0-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) ] + ignore line: [COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/8/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/8/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_67965' '-shared-libgcc' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'] + link line: [ /usr/lib/gcc/arm-linux-gnueabihf/8/collect2 -plugin /usr/lib/gcc/arm-linux-gnueabihf/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper -plugin-opt=-fresolution=/tmp/ccUdAo9s.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu -m armelf_linux_eabi -o cmTC_67965 /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/8 -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/8/../../.. -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crtn.o] + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/collect2] ==> ignore + arg [-plugin] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/liblto_plugin.so] ==> ignore + arg [-plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper] ==> ignore + arg [-plugin-opt=-fresolution=/tmp/ccUdAo9s.res] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [--build-id] ==> ignore + arg [--eh-frame-hdr] ==> ignore + arg [-dynamic-linker] ==> ignore + arg [/lib/ld-linux-armhf.so.3] ==> ignore + arg [-X] ==> ignore + arg [--hash-style=gnu] ==> ignore + arg [-m] ==> ignore + arg [armelf_linux_eabi] ==> ignore + arg [-o] ==> ignore + arg [cmTC_67965] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crt1.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crti.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/crtbegin.o] ==> ignore + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/8] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/8] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/8/../../..] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../..] + arg [-L/lib/arm-linux-gnueabihf] ==> dir [/lib/arm-linux-gnueabihf] + arg [-L/usr/lib/arm-linux-gnueabihf] ==> dir [/usr/lib/arm-linux-gnueabihf] + arg [CMakeFiles/cmTC_67965.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore + arg [-lstdc++] ==> lib [stdc++] + arg [-lm] ==> lib [m] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lc] ==> lib [c] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/crtend.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf/crtn.o] ==> ignore + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/8] ==> [/usr/lib/gcc/arm-linux-gnueabihf/8] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../../arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/8/../../..] ==> [/usr/lib] + collapse library dir [/lib/arm-linux-gnueabihf] ==> [/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + implicit libs: [stdc++;m;gcc_s;gcc;c;gcc_s;gcc] + implicit dirs: [/usr/lib/gcc/arm-linux-gnueabihf/8;/usr/lib/arm-linux-gnueabihf;/usr/lib;/lib/arm-linux-gnueabihf] + implicit fwks: [] + + diff --git a/CMakeFiles/cmake.check_cache b/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000..3dccd73 --- /dev/null +++ b/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4a284d4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.19.0) +project(pipedal VERSION 0.1.0) + +include(CTest) +enable_testing() + +# Frameworks +# catch + +add_subdirectory("react") + +add_subdirectory("src") + + +# add_subdirectory("test") + +# add_test(NAME Test COMMAND piddletest) + +set (REACT_BUILD_DIRECTORY ${PROJECT_SOURCE_DIR}/build/react/build/) + + +install( + DIRECTORY config/ DESTINATION /etc/pipedal/config +) +install ( + DIRECTORY ${REACT_BUILD_DIRECTORY} DESTINATION /etc/pipedal/react +) + +install (FILES ${PROJECT_SOURCE_DIR}/src/template.service + ${PROJECT_SOURCE_DIR}/src/templateShutdown.service + DESTINATION /etc/pipedal ) + +install(CODE +[[ + file(GET_RUNTIME_DEPENDENCIES + EXECUTABLES ${CMAKE_INSTALL_PREFIX}/bin/pipedald ${CMAKE_INSTALL_PREFIX}/bin/pipedalconfig + ) +]] +) + +install( + CODE "execute_process(COMMAND ${CMAKE_INSTALL_PREFIX}/bin/pipedalconfig -install)" +) + + + +set(CPACK_PROJECT_NAME ${PROJECT_NAME}) +set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) +include(CPack) diff --git a/DartConfiguration.tcl b/DartConfiguration.tcl new file mode 100644 index 0000000..1560649 --- /dev/null +++ b/DartConfiguration.tcl @@ -0,0 +1,109 @@ +# This file is configured by CMake automatically as DartConfiguration.tcl +# If you choose not to use CMake, this file may be hand configured, by +# filling in the required variables. + + +# Configuration directories and files +SourceDirectory: /home/patch/src/piddle/test +BuildDirectory: /home/patch/src/piddle + +# Where to place the cost data store +CostDataFile: + +# Site is something like machine.domain, i.e. pragmatic.crd +Site: patchbox + +# Build name is osname-revision-compiler, i.e. Linux-2.4.2-2smp-c++ +BuildName: Linux-c++ + +# Subprojects +LabelsForSubprojects: + +# Submission information +SubmitURL: http:// + +# Dashboard start time +NightlyStartTime: 00:00:00 EDT + +# Commands for the build/test/submit cycle +ConfigureCommand: "/usr/local/bin/cmake" "/home/patch/src/piddle/test" +MakeCommand: /usr/local/bin/cmake --build . --config "${CTEST_CONFIGURATION_TYPE}" +DefaultCTestConfigurationType: Release + +# version control +UpdateVersionOnly: + +# CVS options +# Default is "-d -P -A" +CVSCommand: /usr/bin/cvs +CVSUpdateOptions: -d -A -P + +# Subversion options +SVNCommand: /usr/bin/svn +SVNOptions: +SVNUpdateOptions: + +# Git options +GITCommand: /usr/bin/git +GITInitSubmodules: +GITUpdateOptions: +GITUpdateCustom: + +# Perforce options +P4Command: P4COMMAND-NOTFOUND +P4Client: +P4Options: +P4UpdateOptions: +P4UpdateCustom: + +# Generic update command +UpdateCommand: +UpdateOptions: +UpdateType: + +# Compiler info +Compiler: /usr/bin/c++ +CompilerVersion: 8.3.0 + +# Dynamic analysis (MemCheck) +PurifyCommand: +ValgrindCommand: +ValgrindCommandOptions: +DrMemoryCommand: +DrMemoryCommandOptions: +CudaSanitizerCommand: +CudaSanitizerCommandOptions: +MemoryCheckType: +MemoryCheckSanitizerOptions: +MemoryCheckCommand: MEMORYCHECK_COMMAND-NOTFOUND +MemoryCheckCommandOptions: +MemoryCheckSuppressionFile: + +# Coverage +CoverageCommand: /usr/bin/gcov +CoverageExtraFlags: -l + +# Cluster commands +SlurmBatchCommand: SLURM_SBATCH_COMMAND-NOTFOUND +SlurmRunCommand: SLURM_SRUN_COMMAND-NOTFOUND + +# Testing options +# TimeOut is the amount of time in seconds to wait for processes +# to complete during testing. After TimeOut seconds, the +# process will be summarily terminated. +# Currently set to 25 minutes +TimeOut: 1500 + +# During parallel testing CTest will not start a new test if doing +# so would cause the system load to exceed this value. +TestLoad: + +UseLaunchers: +CurlOptions: +# warning, if you add new options here that have to do with submit, +# you have to update cmCTestSubmitCommand.cxx + +# For CTest submissions that timeout, these options +# specify behavior for retrying the submission +CTestSubmitRetryDelay: 5 +CTestSubmitRetryCount: 3 diff --git a/README.md b/README.md new file mode 100644 index 0000000..37f27a0 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ + + +How to Debug PiPedal. + + +You must stop the pipdeal service before launching a debug instance of pipedal: + + sudo systemctl stop pipedal +or + + pipedalconfig -stop + +But there's no harm in running a debug react server that's configured to connect to the web +socket of a production instance of pipedal. + +PipPedal consists of two subprojects: + + A web application build in React. + + pipedal: a Web server, written in C++, serving a web socket, and pre-built HTML components from the React app. + All audio services are provided by the pipedal process. + +In production, the pipedal web server serves the PiPedal web socket, as well as HTML from the built +react components. While debugging, it is much more convenient to use the React debug server for +React sources, and configure pipedal to serve only the websocket. + +To start the React debug server, from a shell, cd to the react directory, and run "./start". The react debug +server will detect any changes to React sources, and rebuild them automatically (no build step required). +Actual debugging is performed using the Chrome debugger (which is remarkably well integrated with React). + +To get this to work on Raspberry Pi, you will probably have to make a configuration change. + +Edit the file '/etc/sysctl.conf', and add or increase the value for the maximum number of watchable user +files: + fs.inotify.max_user_watches=524288 + +followed by 'sudo sysctl -p'. (VS Code and React both need this change). + +By default, the React app will attempt to contact the pipedal server on ws:*:8080. This can be reconfigured +in the file react/src/public/var/config.json. (The pipedal server intercepts requests for this file and +points the react app at itself in production). The React app will display the message +"Error: Failed to connect to the server", until you start the pipedal websocket server in the debugger. +It's quite reasonable to point the react debug app at a production instance of the pipedal server. + + react/src/public/var/config.json: + { + "socket_server_port": 80, + "socket_server_address": "*", + ... + + } + +Setting socket_server_address to "*" configures the web app to reconnect using the host address the browser +request used to connect to the web app. (e.g. 127.0.0.1, or pipedal.local, &c). If you choose another address, +remember that it is that web browser which will use it to make the connection. + +The original development for this app was done with visual studio code. Open the root project directory in +Visual Studio Code, and it will detect the CMake build files, and configure itself appropriately. Wait for +the CMake plugin in Visual Studio Code to configure itself, after loading. + +Once CMake has configured itself, build and debug commands are avaialble on the CMake toolbar at the +bottom of the Visual Studio Code window. Set the build variant to debug. Set the debug target to "pipedal". +Click on the Build button to build the app. Click on the Debug button to launch a debugger. + +To get the debugger to launch and run correctly, you will need to set commandline parameters for pipedal. +Commandline arguments can be set in the file .vscode/settings.json: + +{ + ... + "cmake.debugConfig": { + "args": [ + "/debugConfig","/build/react/src/build", "-port", "0.0.0.0:8080" + ], + + ... +} + +where is the root directory of the pipedal project. + +The default debug configuration for pipedal is configured to use /var/pipedal for storing working data files, +which allows it to share configuration with a production instance of pipedal. Be warned that the permissioning +for this folder is intricate. If you plan to use the data from a production server, get the production server +installed first so the permissions are set correctly. If you install a production instance later, remove the +entire directory before doing so, to ensure that none of the files in that directory are permissioned +incorrectly. + +You will need to add your userid to the pipedal_d group if you plan to share the /var/pipedal directory. + +You can avoid all of this, by configuring the debug instance to use a data folder in your home directory. Edit +debugConfig/config.json: + +{ + ... + "local_storage_path": "~/var/pipedal", + ... +} + + diff --git a/artifacts/sample_lv2_plugins.json b/artifacts/sample_lv2_plugins.json new file mode 100644 index 0000000..712074b --- /dev/null +++ b/artifacts/sample_lv2_plugins.json @@ -0,0 +1,971 @@ +[ + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubetremelo#tubetremelo", + "name": "GxTubeTremelo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nModel of a vactrol tremolo unit by \"transmogrify\"\nc.f. http://sourceforge.net/apps/phpbb/guitarix/viewtopic.php?f=7&t=44&p=233&hilit=transmogrifox#p233\nhttp://transmogrifox.webs.com/vactrol.m\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "sinewave", + "name": "SineWave", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "depth", + "name": "Depth", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 14, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubevibrato#tubevibrato", + "name": "GxTubeVibrato", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nAttempt at a true vibrato\nAnd it works well!\nSounds very sweet with tubes wrapped\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "sinewave", + "name": "SineWave", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "depth", + "name": "Depth", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 14, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtuner#tuner", + "name": "GxTuner", + "plugin_class": "http://lv2plug.in/ns/lv2core#AnalyserPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "FREQ", + "name": "FREQ", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "REFFREQ", + "name": "REFFREQ", + "min_value": 427, + "max_value": 453, + "default_value": 440, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "TUNER_MODE", + "name": "Tuner Mode", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 8, + "label": "Double Drop D" + }, + { + "value": 7, + "label": "1 and 1/2 Steps Down" + }, + { + "value": 9, + "label": "Drop C" + }, + { + "value": 6, + "label": "Full Step Down" + }, + { + "value": 12, + "label": "Drop A#" + }, + { + "value": 10, + "label": "Drop C#" + }, + { + "value": 11, + "label": "Drop B" + }, + { + "value": 14, + "label": "Open D" + }, + { + "value": 16, + "label": "Open G" + }, + { + "value": 15, + "label": "Open D Minor" + }, + { + "value": 17, + "label": "Open G Minor" + }, + { + "value": 13, + "label": "Drop A" + }, + { + "value": 19, + "label": "Open C#" + }, + { + "value": 20, + "label": "Open C Minor" + }, + { + "value": 21, + "label": "Open E7" + }, + { + "value": 22, + "label": "Open E Minor7" + }, + { + "value": 23, + "label": "Open G Major7" + }, + { + "value": 24, + "label": "Open A Minor" + }, + { + "value": 25, + "label": "Open A Minor7" + }, + { + "value": 26, + "label": "Open A" + }, + { + "value": 27, + "label": "C Tuning" + }, + { + "value": 28, + "label": "C# Tuning" + }, + { + "value": 29, + "label": "Bb Tuning" + }, + { + "value": 30, + "label": "A to A (Baritone)" + }, + { + "value": 31, + "label": "Open Dsus2" + }, + { + "value": 32, + "label": "Open Gsus2" + }, + { + "value": 33, + "label": "G6" + }, + { + "value": 34, + "label": "Overtone" + }, + { + "value": 35, + "label": "Pentatonic" + }, + { + "value": 0, + "label": "(Chromatic)" + }, + { + "value": 36, + "label": "Minor Third" + }, + { + "value": 37, + "label": "Major Third" + }, + { + "value": 38, + "label": "All Fourths" + }, + { + "value": 39, + "label": "Augmented Fourths" + }, + { + "value": 40, + "label": "Slow Motion" + }, + { + "value": 41, + "label": "Admiral" + }, + { + "value": 42, + "label": "Buzzard" + }, + { + "value": 43, + "label": "Face" + }, + { + "value": 44, + "label": "Four and Twenty" + }, + { + "value": 45, + "label": "Ostrich" + }, + { + "value": 1, + "label": "Standard/E" + }, + { + "value": 46, + "label": "Capo 200" + }, + { + "value": 47, + "label": "Balalaika" + }, + { + "value": 48, + "label": "Cittern One" + }, + { + "value": 49, + "label": "Cittern Two" + }, + { + "value": 50, + "label": "Dobro" + }, + { + "value": 51, + "label": "Lefty" + }, + { + "value": 52, + "label": "Mandoguitar" + }, + { + "value": 53, + "label": "Rusty Cage" + }, + { + "value": 54, + "label": "Hardcore" + }, + { + "value": 2, + "label": "Standard/Es" + }, + { + "value": 3, + "label": "Open E" + }, + { + "value": 4, + "label": "Drop D" + }, + { + "value": 5, + "label": "Half Step Down" + }, + { + "value": 18, + "label": "Open C" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "TEMPERAMENT", + "name": "TEMPERAMENT", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "MAXL", + "name": "MAXL", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "RESET", + "name": "RESET", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "CHANNEL", + "name": "CHANNELL", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 6, + "label": "6" + }, + { + "value": 4, + "label": "4" + }, + { + "value": 5, + "label": "5" + }, + { + "value": 0, + "label": "0" + }, + { + "value": 3, + "label": "3" + }, + { + "value": 1, + "label": "1" + }, + { + "value": 2, + "label": "2" + }, + { + "value": 7, + "label": "7" + }, + { + "value": 14, + "label": "14" + }, + { + "value": 16, + "label": "16" + }, + { + "value": 13, + "label": "13" + }, + { + "value": 8, + "label": "8" + }, + { + "value": 15, + "label": "15" + }, + { + "value": 12, + "label": "12" + }, + { + "value": 9, + "label": "9" + }, + { + "value": 11, + "label": "11" + }, + { + "value": 10, + "label": "10" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "MIDI_ON", + "name": "MIDI_ON", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "FASTNOTE", + "name": "FASTNOTE", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "PITCHBEND", + "name": "PITCHBEND", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "SINGLENOTE", + "name": "SINGLENOTE", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "BPM", + "name": "BPM", + "min_value": 0, + "max_value": 360, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "VELOCITY", + "name": "VELOCITY", + "min_value": 0, + "max_value": 127, + "default_value": 64, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "VERIFY", + "name": "VERIFY", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "GATE", + "name": "GATE", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "SYNTHFREQ", + "name": "SYNTHFREQ", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "GAIN", + "name": "GAIN", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "midi_out", + "name": "MIDI Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": true + }, + { + "port_index": 20, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://lv2plug.in/plugins/eg-echo", + "name": "Object Serialization Tester", + "plugin_class": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/urid#map" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/urid#map" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Robin Davies", + "author_homepage": "http://two-play.com/", + "comment": "Plugin used to test text conversion of patch property objects.", + "ports": [ + { + "port_index": 0, + "symbol": "control", + "name": "Control", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "notify", + "name": "Notify", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + } + ] + } +] \ No newline at end of file diff --git a/config/config.json b/config/config.json new file mode 100644 index 0000000..744df81 --- /dev/null +++ b/config/config.json @@ -0,0 +1,31 @@ +{ + /* One or more directories containing LV2 plugins, seperated by ':' */ + "lv2_path": "/usr/modep/lv2:/usr/local/lib/lv2", + + + /* A writable directory in which state files can be stored, preferrably only by the server process. */ + "local_storage_path": "/var/pipedal", + /* whether to lock a process pages into memroy. should be true unless running on a very memory constrained system. + Setting to false will cause unpredictable audio dropouts. + */ + "mlock": true, + + /* Address on which Piddle listens for websocket connections */ + "socketServerAddress": "0.0.0.0:80", + + /* Number of threads to use for servicing websockets */ + "threads" : 5, + + "logHttpRequests": false, + /* { None=0,Error =1,Warning =2,Info = 3, Debug=4} */ + "logLevel": 3, + + /* Maximum filesize to allow when uploading */ + "maxUploadSize": 1048576, + + /* Provide access point capture redirects on this gateway. -- provides automatic browser launching on Access Point access. */ + "accessPointGateway": "172.24.1.0/24", + "accessPointServerAddress": "172.24.1.1" + + +} \ No newline at end of file diff --git a/config/plugin_classes.json b/config/plugin_classes.json new file mode 100644 index 0000000..83125bb --- /dev/null +++ b/config/plugin_classes.json @@ -0,0 +1,276 @@ +{ + "uri": "http://lv2plug.in/ns/lv2core#Plugin", + "display_name": "Plugin", + "parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase", + "plugin_type": "Plugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "display_name": "Delay", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DelayPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "display_name": "Reverb", + "parent_uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "plugin_type": "ReverbPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "display_name": "Distortion", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DistortionPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#WaveshaperPlugin", + "display_name": "Waveshaper", + "parent_uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "plugin_type": "WaveshaperPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "display_name": "Dynamics", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DynamicsPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "display_name": "Amplifier", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "AmplifierPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin", + "display_name": "Compressor", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "CompressorPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#EnvelopePlugin", + "display_name": "Envelope", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "EnvelopePlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ExpanderPlugin", + "display_name": "Expander", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "ExpanderPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#GatePlugin", + "display_name": "Gate", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "GatePlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#LimiterPlugin", + "display_name": "Limiter", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "LimiterPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "display_name": "Filter", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "FilterPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AllpassPlugin", + "display_name": "Allpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "AllpassPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#BandpassPlugin", + "display_name": "Bandpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "BandpassPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#CombPlugin", + "display_name": "Comb", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "CombPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "display_name": "Equaliser", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "EQPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#MultiEQPlugin", + "display_name": "Multiband", + "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "plugin_type": "MultiEQPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ParaEQPlugin", + "display_name": "Parametric", + "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "plugin_type": "ParaEQPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#HighpassPlugin", + "display_name": "Highpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "HighpassPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#LowpassPlugin", + "display_name": "Lowpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "LowpassPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "display_name": "Generator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "GeneratorPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ConstantPlugin", + "display_name": "Constant", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "ConstantPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#InstrumentPlugin", + "display_name": "Instrument", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "InstrumentPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#OscillatorPlugin", + "display_name": "Oscillator", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "OscillatorPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "display_name": "Modulator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "ModulatorPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ChorusPlugin", + "display_name": "Chorus", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "ChorusPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FlangerPlugin", + "display_name": "Flanger", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "FlangerPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#PhaserPlugin", + "display_name": "Phaser", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "PhaserPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "display_name": "Simulator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SimulatorPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin", + "display_name": "Spatial", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SpatialPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", + "display_name": "Spectral", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SpectralPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#PitchPlugin", + "display_name": "Pitch Shifter", + "parent_uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", + "plugin_type": "PitchPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "display_name": "Utility", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "UtilityPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AnalyserPlugin", + "display_name": "Analyser", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "AnalyserPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ConverterPlugin", + "display_name": "Converter", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "ConverterPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FunctionPlugin", + "display_name": "Function", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "FunctionPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#MixerPlugin", + "display_name": "Mixer", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "MixerPlugin", + "children": [ ] + } + ] + } + ] + } \ No newline at end of file diff --git a/configuration_notes.txt b/configuration_notes.txt new file mode 100644 index 0000000..610f501 --- /dev/null +++ b/configuration_notes.txt @@ -0,0 +1,23 @@ + +https://raspberrypi.stackexchange.com/questions/119026/connect-to-wifi-access-point-repeater-when-uplink-is-not-present/119178#119178?newreg=1aefd433cbd64cd4aaadbd0557d59391 + + +/etc/wpa_supplicant/wpa_supplicant.conf: + +add + + p2p_disable=1 + +Delete the network + + + +/etc/dnsmasq.d/dnsmasq.config + +Remove server= line. + +Add 172.24.1.1 piddle to /etc/hosts + + + + diff --git a/debugConfig/config.json b/debugConfig/config.json new file mode 100644 index 0000000..33292e8 --- /dev/null +++ b/debugConfig/config.json @@ -0,0 +1,31 @@ +{ + /* One or more directories containing LV2 plugins, seperated by ':' */ + "lv2_path": "/usr/modep/lv2:/usr/local/lib/lv2", + //"lv2_path" : "/usr/modep/lv2/rkr.lv2", + + + /* A writable directory in which state files can be stored, preferrably only by the server process. */ + "local_storage_path": "/var/pipedal", + /* whether to lock a process pages into memroy. should be true unless running on a very memory constrained system. + Setting to false will cause unpredictable audio dropouts. + */ + "mlock": true, + + /* Address on which Piddle listens for websocket connections */ + "socketServerAddress": "0.0.0.0:8080", + + /* Number of threads to use for servicing websockets */ + "threads" : 5, + + "logHttpRequests": true, + /* { None=0,Error =1,Warning =2,Info = 3, Debug=4} */ + "logLevel": 4, + + /* Maximum filesize to allow when uploading */ + "maxUploadSize": 1048576, + + /* Provide access point capture redirects on this gateway. */ + "accessPointGateway": "192.168.0.0/24", + "accessPointServerAddress" : "192.168.0.23:8080" + +} \ No newline at end of file diff --git a/debugConfig/plugin_classes.json b/debugConfig/plugin_classes.json new file mode 100644 index 0000000..83125bb --- /dev/null +++ b/debugConfig/plugin_classes.json @@ -0,0 +1,276 @@ +{ + "uri": "http://lv2plug.in/ns/lv2core#Plugin", + "display_name": "Plugin", + "parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase", + "plugin_type": "Plugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "display_name": "Delay", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DelayPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "display_name": "Reverb", + "parent_uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "plugin_type": "ReverbPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "display_name": "Distortion", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DistortionPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#WaveshaperPlugin", + "display_name": "Waveshaper", + "parent_uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "plugin_type": "WaveshaperPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "display_name": "Dynamics", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DynamicsPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "display_name": "Amplifier", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "AmplifierPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin", + "display_name": "Compressor", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "CompressorPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#EnvelopePlugin", + "display_name": "Envelope", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "EnvelopePlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ExpanderPlugin", + "display_name": "Expander", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "ExpanderPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#GatePlugin", + "display_name": "Gate", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "GatePlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#LimiterPlugin", + "display_name": "Limiter", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "LimiterPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "display_name": "Filter", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "FilterPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AllpassPlugin", + "display_name": "Allpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "AllpassPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#BandpassPlugin", + "display_name": "Bandpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "BandpassPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#CombPlugin", + "display_name": "Comb", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "CombPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "display_name": "Equaliser", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "EQPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#MultiEQPlugin", + "display_name": "Multiband", + "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "plugin_type": "MultiEQPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ParaEQPlugin", + "display_name": "Parametric", + "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "plugin_type": "ParaEQPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#HighpassPlugin", + "display_name": "Highpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "HighpassPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#LowpassPlugin", + "display_name": "Lowpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "LowpassPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "display_name": "Generator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "GeneratorPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ConstantPlugin", + "display_name": "Constant", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "ConstantPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#InstrumentPlugin", + "display_name": "Instrument", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "InstrumentPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#OscillatorPlugin", + "display_name": "Oscillator", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "OscillatorPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "display_name": "Modulator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "ModulatorPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ChorusPlugin", + "display_name": "Chorus", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "ChorusPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FlangerPlugin", + "display_name": "Flanger", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "FlangerPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#PhaserPlugin", + "display_name": "Phaser", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "PhaserPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "display_name": "Simulator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SimulatorPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin", + "display_name": "Spatial", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SpatialPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", + "display_name": "Spectral", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SpectralPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#PitchPlugin", + "display_name": "Pitch Shifter", + "parent_uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", + "plugin_type": "PitchPlugin", + "children": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "display_name": "Utility", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "UtilityPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AnalyserPlugin", + "display_name": "Analyser", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "AnalyserPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ConverterPlugin", + "display_name": "Converter", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "ConverterPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FunctionPlugin", + "display_name": "Function", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "FunctionPlugin", + "children": [ ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#MixerPlugin", + "display_name": "Mixer", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "MixerPlugin", + "children": [ ] + } + ] + } + ] + } \ No newline at end of file diff --git a/install b/install new file mode 100755 index 0000000..d87a504 --- /dev/null +++ b/install @@ -0,0 +1 @@ +cmake --install /home/patch/src/pipedal/build --prefix /usr/local --config RelWithDebInfo diff --git a/installdbg b/installdbg new file mode 100755 index 0000000..89a3d3b --- /dev/null +++ b/installdbg @@ -0,0 +1 @@ +cmake --install /home/patch/src/pipedal/build --prefix /usr/local --config Debug diff --git a/mk b/mk new file mode 100755 index 0000000..bcea697 --- /dev/null +++ b/mk @@ -0,0 +1 @@ +cmake --build /home/patch/src/pipedal/build --config RelWithDebInfo --target all -j 6 -- diff --git a/react/.gitignore b/react/.gitignore new file mode 100644 index 0000000..4d29575 --- /dev/null +++ b/react/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/react/CMakeLists.txt b/react/CMakeLists.txt new file mode 100644 index 0000000..1e4eb30 --- /dev/null +++ b/react/CMakeLists.txt @@ -0,0 +1,142 @@ + + +find_program(NPM_COMMAND npm) + + +if (CMAKE_BUILD_TYPE MATCHES Debug) + set(BUILD_REACT "echo") +else() + set(BUILD_REACT ${NPM_COMMAND}) +endif() + +set (BUILD_DIRECTORY ${PROJECT_SOURCE_DIR}/build/react/build) +message(STATUS "React Build...") + +add_custom_command( + OUTPUT ${BUILD_DIRECTORY}/index.html + COMMAND ${BUILD_REACT} + ARGS run build + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react + + DEPENDS + src/JackServerSettingsDialog.tsx + src/JackServerSettings.tsx + + src/AboutDialog.tsx + src/App.test.tsx + src/App.tsx + src/Banks.tsx + src/ControlViewFactory.tsx + src/DraggableGrid.tsx + src/Draggable.tsx + src/FullScreenIME.tsx + src/GxTunerControl.tsx + src/IControlViewFactory.tsx + src/index.tsx + src/JackHostStatus.tsx + src/JackStatusView.tsx + src/Jack.tsx + src/LoadPluginDialogBackup.tsx + src/LoadPluginDialog.tsx + src/Lv2Plugin.tsx + src/MainPage.tsx + src/ObservableProperty.tsx + src/PedalBoard.tsx + src/PedalBoardView.tsx + src/Pedal.tsx + src/PiPedalError.tsx + src/PiPedalModel.tsx + src/PiPedalSocket.tsx + src/PluginClass.tsx + src/PluginControl.tsx + src/PluginControlView.tsx + src/PluginIcon.tsx + src/PluginInfoDialog.tsx + src/PresetDialog.tsx + src/PresetSelector.tsx + src/Rect.tsx + src/RenameDialog.tsx + src/ResizeResponsiveComponent.tsx + src/SelectChannelsDialog.tsx + src/SelectHoverBackground.tsx + src/SelectMidiChannelsDialog.tsx + src/SettingsDialog.tsx + src/SplitControlView.tsx + src/SplitUiControls.tsx + src/StringBuilder.tsx + src/SvgPathBuilder.tsx + src/TemporaryDrawer.tsx + src/ToobCabSimView.tsx + src/ToobFrequencyResponseView.tsx + src/ToobInputStageView.tsx + src/ToobToneStackView.tsx + src/Units.tsx + src/Utility.tsx + src/VuMeter.tsx + src/PluginPreset.tsx + + public/logo512.png + public/index.html + public/manifest.json + public/var + public/var/current_pedalboard.json + public/var/uiplugins.json + public/var/config.json + public/var/plugin_classes.json + public/logo192.png + public/serve.json + public/robots.txt + public/sample_lv2_plugins.json + public/logo192x.png + public/img/fx_analyzer.svg + public/img/fx_flanger.svg + public/img/cx_stereo.svg + public/img/fx_split_a.svg + public/img/fx_dial.svg + public/img/drive_file_rename_outline_black_24dp.svg + public/img/fx_filter.svg + public/img/cx_mono.svg + public/img/fx_limiter.svg + public/img/fx_converter.svg + public/img/fx_simulator.svg + public/img/fx_delay.svg + public/img/fx_reverb.svg + public/img/fx_empty.svg + public/img/fx_eq.svg + public/img/edit_banks.svg + public/img/fx_gate.svg + public/img/settings_black_24dp.svg + public/img/help_outline_black_24dp.svg + public/img/fx_oscillator.svg + public/img/fx_split_b.svg + public/img/fx_phaser.svg + public/img/fx_amplifier.svg + public/img/fx_plugin.svg + public/img/ic_drawer.svg + public/img/fx_terminal.svg + public/img/fx_spatial.svg + public/img/fx_pitch.svg + public/img/ic_logo.svg + public/img/fx_flanger2.svg + public/img/fx_function.svg + public/img/fx_lr.svg + public/img/fx_generator.svg + public/img/fx_spectral.svg + public/img/fx_chorus.svg + public/img/fx_utility.svg + public/img/fx_mixer.svg + public/img/ic_presets.svg + public/img/fx_instrument.svg + public/img/fx_modulator.svg + public/img/fx_compressor.svg + public/img/fx_constant.svg + public/img/fx_distortion.svg + public/img/save_bank_as.svg + public/favicon.ico + +) + +add_custom_target ( + ReactBuild ALL + DEPENDS ${BUILD_DIRECTORY}/index.html +) diff --git a/react/README.md b/react/README.md new file mode 100644 index 0000000..b87cb00 --- /dev/null +++ b/react/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/react/package-lock.json b/react/package-lock.json new file mode 100644 index 0000000..a97c828 --- /dev/null +++ b/react/package-lock.json @@ -0,0 +1,16532 @@ +{ + "name": "my-app", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/compat-data": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.5.tgz", + "integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w==" + }, + "@babel/core": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", + "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.1", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.1", + "@babel/parser": "^7.12.3", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@babel/generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", + "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", + "requires": { + "@babel/types": "^7.14.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", + "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", + "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "requires": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.6.tgz", + "integrity": "sha512-Z6gsfGofTxH/+LQXqYEK45kxmcensbzmk/oi8DmaQytlQCgqNZt9XQF8iqlI/SeXWVjaMNxvYvzaYw+kh42mDg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", + "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", + "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", + "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "requires": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.5.tgz", + "integrity": "sha512-UxUeEYPrqH1Q/k0yRku1JE7dyfyehNwT6SVkMHvYvPDv4+uu627VXBckVj891BO8ruKBkiDoGnZf4qPDD8abDQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", + "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", + "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-wrap-function": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-replace-supers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", + "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", + "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==" + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + }, + "@babel/helper-wrap-function": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", + "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", + "requires": { + "@babel/helper-function-name": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helpers": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", + "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "requires": { + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz", + "integrity": "sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==" + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz", + "integrity": "sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.14.5" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz", + "integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", + "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz", + "integrity": "sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.12.1.tgz", + "integrity": "sha512-knNIuusychgYN8fGJHONL0RbFxLGawhXOJNLBk75TniTsZZeA+wdkDuv6wp4lGwzQEKjZi6/WYtnb3udNPmQmQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-decorators": "^7.12.1" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", + "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", + "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", + "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", + "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", + "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", + "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz", + "integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==", + "requires": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.14.5" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", + "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", + "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", + "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", + "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.14.5.tgz", + "integrity": "sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.14.5.tgz", + "integrity": "sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", + "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", + "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", + "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", + "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz", + "integrity": "sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.5.tgz", + "integrity": "sha512-J4VxKAMykM06K/64z9rwiL6xnBHgB1+FVspqvlgCdwD1KUbQNfszeKVVOMh59w3sztHYIZDgnhOC4WbdEfHFDA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", + "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz", + "integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", + "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", + "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", + "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.1.tgz", + "integrity": "sha512-8hAtkmsQb36yMmEtk2JZ9JnVyDSnDOdlB+0nEGzIDLuK4yR3JcEjfuFPYkdEPSh8Id+rAMeBEn+X0iVEyho6Hg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", + "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", + "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "requires": { + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", + "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", + "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", + "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz", + "integrity": "sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==", + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz", + "integrity": "sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==", + "requires": { + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", + "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz", + "integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", + "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", + "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", + "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", + "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.14.5.tgz", + "integrity": "sha512-NBqLEx1GxllIOXJInJAQbrnwwYJsV3WaMHIcOwD8rhYS0AabTWn7kHdHgPgu5RmHLU0q4DMxhAMu8ue/KampgQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.5.tgz", + "integrity": "sha512-07aqY1ChoPgIxsuDviptRpVkWCSbXWmzQqcgy65C6YSFOfPFvb/DX3bBRHh7pCd/PMEEYHYWUTSVkCbkVainYQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.5.tgz", + "integrity": "sha512-7RylxNeDnxc1OleDm0F5Q/BSL+whYRbOAR+bwgCxIr0L32v7UFh/pz1DLMZideAUxKT6eMoS2zQH6fyODLEi8Q==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-jsx": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.14.5.tgz", + "integrity": "sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ==", + "requires": { + "@babel/plugin-transform-react-jsx": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.14.5.tgz", + "integrity": "sha512-M/fmDX6n0cfHK/NLTcPmrfVAORKDhK8tyjDhyxlUjYyPYYO8FRWwuxBA3WBx8kWN/uBUuwGa3s/0+hQ9JIN3Tg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.14.5.tgz", + "integrity": "sha512-1TpSDnD9XR/rQ2tzunBVPThF5poaYT9GqP+of8fAtguYuI/dm2RkrMBDemsxtY0XBzvW7nXjYM0hRyKX9QYj7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.14.5.tgz", + "integrity": "sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", + "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", + "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz", + "integrity": "sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg==", + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", + "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", + "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", + "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", + "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", + "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.14.6.tgz", + "integrity": "sha512-XlTdBq7Awr4FYIzqhmYY80WN0V0azF74DMPyFqVHBvf81ZUgc4X7ZOpx6O8eLDK6iM5cCQzeyJw0ynTaefixRA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.6", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-typescript": "^7.14.5" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", + "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", + "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/preset-env": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz", + "integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==", + "requires": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5", + "@babel/plugin-proposal-async-generator-functions": "^7.14.5", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-class-static-block": "^7.14.5", + "@babel/plugin-proposal-dynamic-import": "^7.14.5", + "@babel/plugin-proposal-export-namespace-from": "^7.14.5", + "@babel/plugin-proposal-json-strings": "^7.14.5", + "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", + "@babel/plugin-proposal-numeric-separator": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.14.5", + "@babel/plugin-proposal-private-methods": "^7.14.5", + "@babel/plugin-proposal-private-property-in-object": "^7.14.5", + "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.14.5", + "@babel/plugin-transform-async-to-generator": "^7.14.5", + "@babel/plugin-transform-block-scoped-functions": "^7.14.5", + "@babel/plugin-transform-block-scoping": "^7.14.5", + "@babel/plugin-transform-classes": "^7.14.5", + "@babel/plugin-transform-computed-properties": "^7.14.5", + "@babel/plugin-transform-destructuring": "^7.14.5", + "@babel/plugin-transform-dotall-regex": "^7.14.5", + "@babel/plugin-transform-duplicate-keys": "^7.14.5", + "@babel/plugin-transform-exponentiation-operator": "^7.14.5", + "@babel/plugin-transform-for-of": "^7.14.5", + "@babel/plugin-transform-function-name": "^7.14.5", + "@babel/plugin-transform-literals": "^7.14.5", + "@babel/plugin-transform-member-expression-literals": "^7.14.5", + "@babel/plugin-transform-modules-amd": "^7.14.5", + "@babel/plugin-transform-modules-commonjs": "^7.14.5", + "@babel/plugin-transform-modules-systemjs": "^7.14.5", + "@babel/plugin-transform-modules-umd": "^7.14.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5", + "@babel/plugin-transform-new-target": "^7.14.5", + "@babel/plugin-transform-object-super": "^7.14.5", + "@babel/plugin-transform-parameters": "^7.14.5", + "@babel/plugin-transform-property-literals": "^7.14.5", + "@babel/plugin-transform-regenerator": "^7.14.5", + "@babel/plugin-transform-reserved-words": "^7.14.5", + "@babel/plugin-transform-shorthand-properties": "^7.14.5", + "@babel/plugin-transform-spread": "^7.14.5", + "@babel/plugin-transform-sticky-regex": "^7.14.5", + "@babel/plugin-transform-template-literals": "^7.14.5", + "@babel/plugin-transform-typeof-symbol": "^7.14.5", + "@babel/plugin-transform-unicode-escapes": "^7.14.5", + "@babel/plugin-transform-unicode-regex": "^7.14.5", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.14.5", + "babel-plugin-polyfill-corejs2": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.2", + "babel-plugin-polyfill-regenerator": "^0.2.2", + "core-js-compat": "^3.14.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.14.5.tgz", + "integrity": "sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-transform-react-display-name": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.5", + "@babel/plugin-transform-react-jsx-development": "^7.14.5", + "@babel/plugin-transform-react-pure-annotations": "^7.14.5" + } + }, + "@babel/preset-typescript": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.12.1.tgz", + "integrity": "sha512-hNK/DhmoJPsksdHuI/RVrcEws7GN5eamhi28JkO52MqIxU8Z0QpmiSOQxZHWOHV7I3P4UjHV97ay4TcamMA6Kw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.12.1" + } + }, + "@babel/runtime": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", + "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.6.tgz", + "integrity": "sha512-Xl8SPYtdjcMoCsIM4teyVRg7jIcgl8F2kRtoCcXuHzXswt9UxZCS6BzRo8fcnCuP6u2XtPgvyonmEPF57Kxo9Q==", + "requires": { + "core-js-pure": "^3.14.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/traverse": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.5.tgz", + "integrity": "sha512-G3BiS15vevepdmFqmUc9X+64y0viZYygubAMO8SvBmKARuF6CPSZtH4Ng9vi/lrWlZFGe3FWdXNy835akH8Glg==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@csstools/convert-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", + "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" + }, + "@csstools/normalize.css": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", + "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + } + } + }, + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" + }, + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" + }, + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "requires": { + "@hapi/hoek": "^8.3.0" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + }, + "@jest/console": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/core": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "@jest/environment": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "requires": { + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" + } + }, + "@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "requires": { + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "requires": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + } + }, + "@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "node-notifier": "^8.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "@jest/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "requires": { + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + } + }, + "@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@material-ui/core": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz", + "integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.4", + "@material-ui/system": "^4.11.3", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/icons": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", + "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==", + "requires": { + "@babel/runtime": "^7.4.4" + } + }, + "@material-ui/styles": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", + "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.2", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.17", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz", + "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==" + } + } + }, + "@material-ui/system": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz", + "integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.2", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.17", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz", + "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" + }, + "@material-ui/utils": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", + "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz", + "integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==", + "requires": { + "ansi-html": "^0.0.7", + "error-stack-parser": "^2.0.6", + "html-entities": "^1.2.1", + "native-url": "^0.2.6", + "schema-utils": "^2.6.5", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", + "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==", + "requires": { + "@rollup/pluginutils": "^3.0.8", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.14.2" + } + }, + "@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + } + } + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@surma/rollup-plugin-off-main-thread": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz", + "integrity": "sha512-yBMPqmd1yEJo/280PAMkychuaALyQ9Lkb5q1ck3mjJrFuEobIfhnQ4J3mbvBoISmR3SWMWV+cGB/I0lCQee79A==", + "requires": { + "ejs": "^2.6.1", + "magic-string": "^0.25.0" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==" + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==" + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==" + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==" + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==" + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==" + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==" + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==" + }, + "@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + } + }, + "@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "requires": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "requires": { + "@babel/types": "^7.12.6" + } + }, + "@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "requires": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + } + }, + "@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "requires": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "requires": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + } + }, + "@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/jest-dom": { + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", + "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "requires": { + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^4.2.2", + "chalk": "^3.0.0", + "css": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "requires": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/react": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", + "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "requires": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^7.28.1" + } + }, + "@testing-library/user-event": { + "version": "12.8.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", + "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", + "requires": { + "@babel/runtime": "^7.12.5" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@types/aria-query": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", + "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" + }, + "@types/babel__core": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/eslint": { + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", + "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/estree": { + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", + "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==" + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "requires": { + "@types/node": "*" + } + }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==" + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "26.0.23", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", + "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", + "requires": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" + }, + "@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" + }, + "@types/node": { + "version": "12.20.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.15.tgz", + "integrity": "sha512-F6S4Chv4JicJmyrwlDkxUdGNSplsQdGwp1A0AJloEVDirWdZOAiRHhovDlsFkKUrquUXhz1imJhXHsf59auyAg==" + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-hkc1DATxFLQo4VxPDpMH1gCkPpBbpOoJ/4nhuXw4n63/0R6bCpQECj4+K226UJ4JO/eJQz+1mC2I7JsWanAdQw==" + }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" + }, + "@types/react": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.11.tgz", + "integrity": "sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.8.tgz", + "integrity": "sha512-0ohAiJAx1DAUEcY9UopnfwCE9sSMDGnY/oXjWMax6g3RpzmTt2GMyMVAXcbn0mo8XAff0SbQJl2/SBU+hjSZ1A==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==", + "requires": { + "@types/react": "*" + } + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/scheduler": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==" + }, + "@types/stack-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", + "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==" + }, + "@types/tapable": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz", + "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==" + }, + "@types/testing-library__jest-dom": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.0.tgz", + "integrity": "sha512-l2P2GO+hFF4Liye+fAajT1qBqvZOiL79YMpEvgGs1xTK7hECxBI8Wz4J7ntACJNiJ9r0vXQqYovroXRLPDja6A==", + "requires": { + "@types/jest": "*" + } + }, + "@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@types/webpack": { + "version": "4.41.29", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.29.tgz", + "integrity": "sha512-6pLaORaVNZxiB3FSHbyBiWM7QdazAWda1zvAq4SbZObZqHSDbWLi62iFdblVea6SK9eyBIVp5yHhKt/yNQdR7Q==", + "requires": { + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "anymatch": "^3.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "@types/yargs": { + "version": "15.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz", + "integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==", + "requires": { + "@typescript-eslint/experimental-utils": "4.27.0", + "@typescript-eslint/scope-manager": "4.27.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.21", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz", + "integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==", + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.27.0", + "@typescript-eslint/types": "4.27.0", + "@typescript-eslint/typescript-estree": "4.27.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz", + "integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==", + "requires": { + "@typescript-eslint/scope-manager": "4.27.0", + "@typescript-eslint/types": "4.27.0", + "@typescript-eslint/typescript-estree": "4.27.0", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz", + "integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==", + "requires": { + "@typescript-eslint/types": "4.27.0", + "@typescript-eslint/visitor-keys": "4.27.0" + } + }, + "@typescript-eslint/types": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz", + "integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA==" + }, + "@typescript-eslint/typescript-estree": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz", + "integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==", + "requires": { + "@typescript-eslint/types": "4.27.0", + "@typescript-eslint/visitor-keys": "4.27.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz", + "integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==", + "requires": { + "@typescript-eslint/types": "4.27.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==" + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + }, + "adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=" + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "axe-core": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.2.tgz", + "integrity": "sha512-OKRkKM4ojMEZRJ5UNJHmq9tht7cEnRnqKG6KyB/trYws00Xtkv12mHtlJ0SK7cmuNbrU8dPUova3ELTuilfBbw==" + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "requires": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + } + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", + "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==" + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", + "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.2", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz", + "integrity": "sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2", + "core-js-compat": "^3.14.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", + "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2" + } + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "requires": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "babel-preset-react-app": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.0.tgz", + "integrity": "sha512-itL2z8v16khpuKutx5IH8UdCdSTuzrOhRFTEdIhveZ2i1iBKDrVE0ATa4sFVy+02GLucZNVBWtoarXBy0Msdpg==", + "requires": { + "@babel/core": "7.12.3", + "@babel/plugin-proposal-class-properties": "7.12.1", + "@babel/plugin-proposal-decorators": "7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.12.1", + "@babel/plugin-proposal-numeric-separator": "7.12.1", + "@babel/plugin-proposal-optional-chaining": "7.12.1", + "@babel/plugin-transform-flow-strip-types": "7.12.1", + "@babel/plugin-transform-react-display-name": "7.12.1", + "@babel/plugin-transform-runtime": "7.12.1", + "@babel/preset-env": "7.12.1", + "@babel/preset-react": "7.12.1", + "@babel/preset-typescript": "7.12.1", + "@babel/runtime": "7.12.1", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/plugin-proposal-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", + "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", + "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.1.tgz", + "integrity": "sha512-MR7Ok+Af3OhNTCxYVjJZHS0t97ydnJZt/DbR4WISO39iDnhiD8XHrY12xuSJ90FFEGjir0Fzyyn7g/zY6hxbxA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz", + "integrity": "sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz", + "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.1.tgz", + "integrity": "sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg==", + "requires": { + "@babel/compat-data": "^7.12.1", + "@babel/helper-compilation-targets": "^7.12.1", + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.1", + "@babel/plugin-proposal-async-generator-functions": "^7.12.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-dynamic-import": "^7.12.1", + "@babel/plugin-proposal-export-namespace-from": "^7.12.1", + "@babel/plugin-proposal-json-strings": "^7.12.1", + "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.1", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.12.1", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-async-to-generator": "^7.12.1", + "@babel/plugin-transform-block-scoped-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-computed-properties": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-dotall-regex": "^7.12.1", + "@babel/plugin-transform-duplicate-keys": "^7.12.1", + "@babel/plugin-transform-exponentiation-operator": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-function-name": "^7.12.1", + "@babel/plugin-transform-literals": "^7.12.1", + "@babel/plugin-transform-member-expression-literals": "^7.12.1", + "@babel/plugin-transform-modules-amd": "^7.12.1", + "@babel/plugin-transform-modules-commonjs": "^7.12.1", + "@babel/plugin-transform-modules-systemjs": "^7.12.1", + "@babel/plugin-transform-modules-umd": "^7.12.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", + "@babel/plugin-transform-new-target": "^7.12.1", + "@babel/plugin-transform-object-super": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-property-literals": "^7.12.1", + "@babel/plugin-transform-regenerator": "^7.12.1", + "@babel/plugin-transform-reserved-words": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-sticky-regex": "^7.12.1", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@babel/plugin-transform-unicode-escapes": "^7.12.1", + "@babel/plugin-transform-unicode-regex": "^7.12.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.12.1", + "core-js-compat": "^3.6.2", + "semver": "^5.5.0" + } + }, + "@babel/preset-react": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.1.tgz", + "integrity": "sha512-euCExymHCi0qB9u5fKw7rvlw7AZSjw/NaB9h7EkdTt5+yHRrXdiRTh7fkG3uBPpJg82CqLfp1LHLqWGSCrab+g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-react-display-name": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.1", + "@babel/plugin-transform-react-jsx-development": "^7.12.1", + "@babel/plugin-transform-react-jsx-self": "^7.12.1", + "@babel/plugin-transform-react-jsx-source": "^7.12.1", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + } + }, + "@babel/runtime": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", + "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + }, + "bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "requires": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cacache": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.2.0.tgz", + "integrity": "sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw==", + "requires": { + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001238", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001238.tgz", + "integrity": "sha512-bZGam2MxEt7YNsa2VwshqWQMwrYs5tR5WZQRYSuFxsBQunWjBuXhN4cS9nV5FFb1Z9y+DoQcQ0COyQbv6A+CKw==" + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "requires": { + "rsvp": "^4.8.4" + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" + }, + "check-types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", + "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==" + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "optional": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "requires": { + "arity-n": "^1.0.4" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==" + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.14.0.tgz", + "integrity": "sha512-3s+ed8er9ahK+zJpp9ZtuVcDoFzHNiZsPbNAAE4KXgrRHbjSqqNN6xGSXq6bq7TZIbKj4NLrLb6bJ5i+vSVjHA==" + }, + "core-js-compat": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz", + "integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==", + "requires": { + "browserslist": "^4.16.6", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, + "core-js-pure": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.14.0.tgz", + "integrity": "sha512-YVh+LN2FgNU0odThzm61BsdkwrbrchumFq3oztnE9vTKC4KS2fvnPmcx8t6jnqAyOTCTF4ZSiuK8Qhh7SNcL4g==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "css-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz", + "integrity": "sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==", + "requires": { + "camelcase": "^6.0.0", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^2.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.3", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.1", + "semver": "^7.3.2" + } + }, + "css-prefers-color-scheme": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", + "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" + }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" + }, + "cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", + "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.8", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, + "cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=" + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=" + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "damerau-levenshtein": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", + "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==" + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-accessibility-api": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", + "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==" + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } + } + }, + "domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "requires": { + "domelementtype": "^2.2.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + } + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" + }, + "electron-to-chromium": { + "version": "1.3.752", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz", + "integrity": "sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A==" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emittery": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "requires": { + "stackframe": "^1.1.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==", + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-react-app": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", + "integrity": "sha512-bpoAAC+YRfzq0dsTk+6v9aHm/uqnDwayNAXleMypGl6CpxI9oXXscVHo4fk3eJPIn+rsbtNetB4r/ZIidFIE8A==", + "requires": { + "confusing-browser-globals": "^1.0.10" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-flowtype": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.7.2.tgz", + "integrity": "sha512-7Oq/N0+3nijBnYWQYzz/Mp/7ZCpwxYvClRyW/PLAmimY9uLCBvoXsNsERcJdkKceyOjgRbFhhxs058KTrne9Mg==", + "requires": { + "lodash": "^4.17.15", + "string-natural-compare": "^3.0.1" + } + }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-jest": { + "version": "24.3.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.3.6.tgz", + "integrity": "sha512-WOVH4TIaBLIeCX576rLcOgjNXqP+jNlCiEmRgFTfQtJ52DpwnIQKAVGlGPAN7CZ33bW6eNfHD6s8ZbEUTQubJg==", + "requires": { + "@typescript-eslint/experimental-utils": "^4.0.1" + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "requires": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + } + } + }, + "eslint-plugin-react": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", + "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==" + }, + "eslint-plugin-testing-library": { + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.2.tgz", + "integrity": "sha512-WAmOCt7EbF1XM8XfbCKAEzAPnShkNSwcIsAD2jHdsMUT9mZJPjLCG7pMzbcC8kK366NOuGip8HKLDC+Xk4yIdA==", + "requires": { + "@typescript-eslint/experimental-utils": "^3.10.1" + }, + "dependencies": { + "@typescript-eslint/experimental-utils": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz", + "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/typescript-estree": "3.10.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/types": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz", + "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==" + }, + "@typescript-eslint/typescript-estree": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz", + "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", + "requires": { + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/visitor-keys": "3.10.1", + "debug": "^4.1.1", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz", + "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "eslint-webpack-plugin": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.5.4.tgz", + "integrity": "sha512-7rYh0m76KyKSDE+B+2PUQrlNS4HJ51t3WKpkJg6vo2jFMbEPTG99cBV0Dm7LXSHucN4WGCG65wQcRiTFrj7iWw==", + "requires": { + "@types/eslint": "^7.2.6", + "arrify": "^2.0.1", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==" + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "expect": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "requires": { + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "requires": { + "bser": "2.1.1" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-loader": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.1.1.tgz", + "integrity": "sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "filesize": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", + "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==" + }, + "flatten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "fork-ts-checker-webpack-plugin": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz", + "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", + "requires": { + "@babel/code-frame": "^7.5.5", + "chalk": "^2.4.1", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "optional": true + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==" + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + } + }, + "html-webpack-plugin": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz", + "integrity": "sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==", + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + } + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "requires": { + "postcss": "^7.0.14" + } + }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "immer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "dependencies": { + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indefinite-observable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz", + "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==", + "requires": { + "symbol-observable": "1.2.0" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==" + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz", + "integrity": "sha512-jxTmrvuecVISvKFFhOkjsWRZV7sFqdSUAd1ajOKY+/QE/aLBVstsJ/dX8GczLzwiT6ZEwwmZqtCUHLHHQVzcfA==", + "requires": { + "@jest/core": "^26.6.0", + "import-local": "^3.0.2", + "jest-cli": "^26.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "requires": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-changed-files": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "requires": { + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "jest-circus": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-26.6.0.tgz", + "integrity": "sha512-L2/Y9szN6FJPWFK8kzWXwfp+FOR7xq0cUL4lIsdbIdwz3Vh6P1nrpcqOleSzr28zOtSHQNV9Z7Tl+KkuK7t5Ng==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.0", + "@jest/test-result": "^26.6.0", + "@jest/types": "^26.6.0", + "@types/babel__traverse": "^7.0.4", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^26.6.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.0", + "jest-matcher-utils": "^26.6.0", + "jest-message-util": "^26.6.0", + "jest-runner": "^26.6.0", + "jest-runtime": "^26.6.0", + "jest-snapshot": "^26.6.0", + "jest-util": "^26.6.0", + "pretty-format": "^26.6.0", + "stack-utils": "^2.0.2", + "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-config": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-docblock": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-environment-jsdom": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "requires": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2", + "jsdom": "^16.4.0" + } + }, + "jest-environment-node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "requires": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==" + }, + "jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "requires": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^26.6.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2", + "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-leak-detector": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "requires": { + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + } + }, + "jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-mock": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==" + }, + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==" + }, + "jest-resolve": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.0.tgz", + "integrity": "sha512-tRAz2bwraHufNp+CCmAD8ciyCpXCs1NQxB5EJAmtCFy6BN81loFEGWKzYu26Y62lAJJe4X4jg36Kf+NsQyiStQ==", + "requires": { + "@jest/types": "^26.6.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.0", + "read-pkg-up": "^7.0.1", + "resolve": "^1.17.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "jest-resolve-dependencies": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "requires": { + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" + } + }, + "jest-runner": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "jest-runtime": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^0.6.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", + "chalk": "^4.0.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^26.6.2", + "semver": "^7.3.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + } + } + }, + "jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-validate": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "requires": { + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watch-typeahead": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.6.1.tgz", + "integrity": "sha512-ITVnHhj3Jd/QkqQcTqZfRgjfyRhDFM/auzgVo2RKvSwi18YMvh0WvXDJFoFED6c7jd/5jxtu4kSOb9PTu2cPVg==", + "requires": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^26.0.0", + "jest-watcher": "^26.3.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watcher": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "requires": { + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsdom": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", + "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.5", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.0.tgz", + "integrity": "sha512-ULr0LDaEqQrMFGyQ3bhJkLsbtrQ8QibAseGZeaSUiT/6zb9IvIkomWHJIvgvwad+hinRAgsI51JcWk2yvwyL+w==" + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jss": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.6.0.tgz", + "integrity": "sha512-n7SHdCozmxnzYGXBHe0NsO0eUf9TvsHVq2MXvi4JmTn3x5raynodDVE/9VQmBdWFyyj9HpHZ2B4xNZ7MMy7lkw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "indefinite-observable": "^2.0.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.6.0.tgz", + "integrity": "sha512-JdLpA3aI/npwj3nDMKk308pvnhoSzkW3PXlbgHAzfx0yHWnPPVUjPhXFtLJzgKZge8lsfkUxvYSQ3X2OYIFU6A==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.6.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.6.0.tgz", + "integrity": "sha512-7y4cAScMHAxvslBK2JRK37ES9UT0YfTIXWgzUWD5euvR+JR3q+o8sQKzBw7GmkQRfZijrRJKNTiSt1PBsLI9/w==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-global": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.6.0.tgz", + "integrity": "sha512-I3w7ji/UXPi3VuWrTCbHG9rVCgB4yoBQLehGDTmsnDfXQb3r1l3WIdcO8JFp9m0YMmyy2CU7UOV6oPI7/Tmu+w==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-nested": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.6.0.tgz", + "integrity": "sha512-fOFQWgd98H89E6aJSNkEh2fAXquC9aZcAVjSw4q4RoQ9gU++emg18encR4AT4OOIFl4lQwt5nEyBBRn9V1Rk8g==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.6.0.tgz", + "integrity": "sha512-oMCe7hgho2FllNc60d9VAfdtMrZPo9n1Iu6RNa+3p9n0Bkvnv/XX5San8fTPujrTBScPqv9mOE0nWVvIaohNuw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.6.0.tgz", + "integrity": "sha512-TKFqhRTDHN1QrPTMYRlIQUOC2FFQb271+AbnetURKlGvRl/eWLswcgHQajwuxI464uZk91sPiTtdGi7r7XaWfA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.6.0.tgz", + "integrity": "sha512-doJ7MouBXT1lypLLctCwb4nJ6lDYqrTfVS3LtXgox42Xz0gXusXIIDboeh6UwnSmox90QpVnub7au8ybrb0krQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.6.0" + } + }, + "jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "requires": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==" + }, + "language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==" + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=" + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "requires": { + "tmpl": "1.0.x" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "requires": { + "mime-db": "1.48.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" + }, + "mini-css-extract-plugin": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz", + "integrity": "sha512-n9BA8LonkOkW1/zn+IbLPQmovsL0wMb9yx75fMJQZf2X1Zoec9yTZtyMePcyu19wPkmFbzZZA6fLTotpFhQsOA==", + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "nanoid": { + "version": "3.1.23", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", + "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "native-url": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/native-url/-/native-url-0.2.6.tgz", + "integrity": "sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA==", + "requires": { + "querystring": "^0.2.0" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" + }, + "node-notifier": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "optional": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "object.fromentries": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", + "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + } + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz", + "integrity": "sha512-wqd6FdI2a5/FdoiCNNkEvLeA//lHHfG24Ln2Xm2qqdIk4aOlsR18jwpyOihqQ8849W3qu2DX8fOYxpvTMj+93A==", + "requires": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "pnp-webpack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", + "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", + "requires": { + "ts-pnp": "^1.1.6" + } + }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", + "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^6.0.2" + } + }, + "postcss-browser-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", + "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", + "requires": { + "postcss": "^7" + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "postcss-color-functional-notation": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", + "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-gray": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", + "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-hex-alpha": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", + "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", + "requires": { + "postcss": "^7.0.14", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-color-mod-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", + "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", + "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-custom-media": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", + "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", + "requires": { + "postcss": "^7.0.14" + } + }, + "postcss-custom-properties": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", + "requires": { + "postcss": "^7.0.17", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-custom-selectors": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", + "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-dir-pseudo-class": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", + "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-double-position-gradients": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", + "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", + "requires": { + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-env-function": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", + "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-flexbugs-fixes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz", + "integrity": "sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==", + "requires": { + "postcss": "^7.0.26" + } + }, + "postcss-focus-visible": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", + "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-focus-within": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", + "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-font-variant": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", + "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-gap-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", + "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-image-set-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", + "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-initial": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz", + "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-lab-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", + "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-logical": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", + "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-media-minmax": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", + "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "postcss-nesting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", + "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-normalize": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-8.0.1.tgz", + "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==", + "requires": { + "@csstools/normalize.css": "^10.1.0", + "browserslist": "^4.6.2", + "postcss": "^7.0.17", + "postcss-browser-comments": "^3.0.0", + "sanitize.css": "^10.0.0" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-overflow-shorthand": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", + "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-page-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", + "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-place": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", + "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-preset-env": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", + "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", + "requires": { + "autoprefixer": "^9.6.1", + "browserslist": "^4.6.4", + "caniuse-lite": "^1.0.30000981", + "css-blank-pseudo": "^0.1.4", + "css-has-pseudo": "^0.10.0", + "css-prefers-color-scheme": "^3.1.1", + "cssdb": "^4.4.0", + "postcss": "^7.0.17", + "postcss-attribute-case-insensitive": "^4.0.1", + "postcss-color-functional-notation": "^2.0.1", + "postcss-color-gray": "^5.0.0", + "postcss-color-hex-alpha": "^5.0.3", + "postcss-color-mod-function": "^3.0.3", + "postcss-color-rebeccapurple": "^4.0.1", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^8.0.11", + "postcss-custom-selectors": "^5.1.2", + "postcss-dir-pseudo-class": "^5.0.0", + "postcss-double-position-gradients": "^1.0.0", + "postcss-env-function": "^2.0.2", + "postcss-focus-visible": "^4.0.0", + "postcss-focus-within": "^3.0.0", + "postcss-font-variant": "^4.0.0", + "postcss-gap-properties": "^2.0.0", + "postcss-image-set-function": "^3.0.1", + "postcss-initial": "^3.0.0", + "postcss-lab-function": "^2.0.1", + "postcss-logical": "^3.0.0", + "postcss-media-minmax": "^4.0.0", + "postcss-nesting": "^7.0.0", + "postcss-overflow-shorthand": "^2.0.0", + "postcss-page-break": "^2.0.0", + "postcss-place": "^4.0.1", + "postcss-pseudo-class-any-link": "^6.0.0", + "postcss-replace-overflow-wrap": "^3.0.0", + "postcss-selector-matches": "^4.0.0", + "postcss-selector-not": "^4.0.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", + "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-replace-overflow-wrap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", + "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-safe-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-5.0.2.tgz", + "integrity": "sha512-jDUfCPJbKOABhwpUKcqCVbbXiloe/QXMcbJ6Iipf3sDIihEzTqRCeMBfRaOHxhBuTYqtASrI1KJWxzztZU4qUQ==", + "requires": { + "postcss": "^8.1.0" + }, + "dependencies": { + "postcss": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", + "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", + "requires": { + "colorette": "^1.2.2", + "nanoid": "^3.1.23", + "source-map-js": "^0.6.2" + } + } + } + }, + "postcss-selector-matches": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", + "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-not": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", + "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", + "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", + "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + }, + "postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "requires": { + "asap": "~2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", + "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + } + } + }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-app-polyfill": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz", + "integrity": "sha512-0sF4ny9v/B7s6aoehwze9vJNWcmCemAUYBVasscVr92+UYiEqDXOxfKjXN685mDaMRNF3WdhHQs76oTODMocFA==", + "requires": { + "core-js": "^3.6.5", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "whatwg-fetch": "^3.4.1" + } + }, + "react-dev-utils": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", + "integrity": "sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A==", + "requires": { + "@babel/code-frame": "7.10.4", + "address": "1.1.2", + "browserslist": "4.14.2", + "chalk": "2.4.2", + "cross-spawn": "7.0.3", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.1.0", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "4.1.6", + "global-modules": "2.0.0", + "globby": "11.0.1", + "gzip-size": "5.1.1", + "immer": "8.0.1", + "is-root": "2.1.0", + "loader-utils": "2.0.0", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "prompts": "2.4.0", + "react-error-overlay": "^6.0.9", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "browserslist": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz", + "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==", + "requires": { + "caniuse-lite": "^1.0.30001125", + "electron-to-chromium": "^1.3.564", + "escalade": "^3.0.2", + "node-releases": "^1.1.61" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + } + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-refresh": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", + "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" + }, + "react-scripts": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz", + "integrity": "sha512-S5eO4vjUzUisvkIPB7jVsKtuH2HhWcASREYWHAQ1FP5HyCv3xgn+wpILAEWkmy+A+tTNbSZClhxjT3qz6g4L1A==", + "requires": { + "@babel/core": "7.12.3", + "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", + "@svgr/webpack": "5.5.0", + "@typescript-eslint/eslint-plugin": "^4.5.0", + "@typescript-eslint/parser": "^4.5.0", + "babel-eslint": "^10.1.0", + "babel-jest": "^26.6.0", + "babel-loader": "8.1.0", + "babel-plugin-named-asset-import": "^0.3.7", + "babel-preset-react-app": "^10.0.0", + "bfj": "^7.0.2", + "camelcase": "^6.1.0", + "case-sensitive-paths-webpack-plugin": "2.3.0", + "css-loader": "4.3.0", + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "eslint": "^7.11.0", + "eslint-config-react-app": "^6.0.0", + "eslint-plugin-flowtype": "^5.2.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jest": "^24.1.0", + "eslint-plugin-jsx-a11y": "^6.3.1", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-testing-library": "^3.9.2", + "eslint-webpack-plugin": "^2.5.2", + "file-loader": "6.1.1", + "fs-extra": "^9.0.1", + "fsevents": "^2.1.3", + "html-webpack-plugin": "4.5.0", + "identity-obj-proxy": "3.0.0", + "jest": "26.6.0", + "jest-circus": "26.6.0", + "jest-resolve": "26.6.0", + "jest-watch-typeahead": "0.6.1", + "mini-css-extract-plugin": "0.11.3", + "optimize-css-assets-webpack-plugin": "5.0.4", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "4.2.1", + "postcss-loader": "3.0.0", + "postcss-normalize": "8.0.1", + "postcss-preset-env": "6.7.0", + "postcss-safe-parser": "5.0.2", + "prompts": "2.4.0", + "react-app-polyfill": "^2.0.0", + "react-dev-utils": "^11.0.3", + "react-refresh": "^0.8.3", + "resolve": "1.18.1", + "resolve-url-loader": "^3.1.2", + "sass-loader": "^10.0.5", + "semver": "7.3.2", + "style-loader": "1.3.0", + "terser-webpack-plugin": "4.2.3", + "ts-pnp": "1.2.0", + "url-loader": "4.1.1", + "webpack": "4.44.2", + "webpack-dev-server": "3.11.1", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "5.1.4" + } + }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "requires": { + "minimatch": "3.0.4" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + }, + "regjsparser": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + } + }, + "css-what": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==" + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resolve": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", + "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "requires": { + "is-core-module": "^2.0.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "resolve-url-loader": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.3.tgz", + "integrity": "sha512-WbDSNFiKPPLem1ln+EVTE+bFUBdTTytfQZWbmghroaFNFaAVmGq0Saqw6F/306CwgPXsGwXVxbODE+3xAo/YbA==", + "requires": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.21", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "requires": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=" + } + } + }, + "rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=" + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", + "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "rollup-plugin-babel": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", + "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-terser": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz", + "integrity": "sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w==", + "requires": { + "@babel/code-frame": "^7.5.5", + "jest-worker": "^24.9.0", + "rollup-pluginutils": "^2.8.2", + "serialize-javascript": "^4.0.0", + "terser": "^4.6.2" + }, + "dependencies": { + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" + } + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "sanitize.css": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", + "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==" + }, + "sass-loader": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.2.0.tgz", + "integrity": "sha512-kUceLzC1gIHz0zNJPpqRsJyisWatGYNFRmv2CKZK2/ngMJgLqxTbXwe/hJ85luyvZkgqU3VlJ33UVF2T/0g6mw==", + "requires": { + "klona": "^2.0.4", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0", + "semver": "^7.3.2" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "selfsigned": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", + "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "optional": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "sockjs-client": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz", + "integrity": "sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==", + "requires": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", + "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "requires": { + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.matchall": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", + "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=" + }, + "tempy": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz", + "integrity": "sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==", + "requires": { + "temp-dir": "^1.0.0", + "type-fest": "^0.3.1", + "unique-string": "^1.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==" + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "terser-webpack-plugin": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", + "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", + "requires": { + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "jest-worker": "^26.5.0", + "p-limit": "^3.0.2", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.3.4", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "terser": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", + "integrity": "sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "dependencies": { + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "requires": { + "punycode": "^2.1.1" + } + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==" + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==" + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + } + } + }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + }, + "v8-to-istanbul": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "requires": { + "makeerror": "1.0.x" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "web-vitals": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz", + "integrity": "sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig==" + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, + "webpack": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", + "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.3.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + } + } + }, + "webpack-dev-server": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.1.tgz", + "integrity": "sha512-u4R3mRzZkbxQVa+MBWi2uVpB5W59H3ekZAJsQlKUTdl7Elcah2EhygTPLmeFXybQkf9i2+L0kn7ik9SnXa6ihQ==", + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "webpack-manifest-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz", + "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==", + "requires": { + "fs-extra": "^7.0.0", + "lodash": ">=3.5 <5", + "object.entries": "^1.1.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.6.0.tgz", + "integrity": "sha512-os0KkeeqUOl7ccdDT1qqUcS4KH4tcBTSKK5Nl5WKb2lyxInIZ/CpjkqKa1Ss12mjfdcRX9mHmPPs7/SxG1Hbdw==", + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "workbox-background-sync": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-5.1.4.tgz", + "integrity": "sha512-AH6x5pYq4vwQvfRDWH+vfOePfPIYQ00nCEB7dJRU1e0n9+9HMRyvI63FlDvtFT2AvXVRsXvUt7DNMEToyJLpSA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-broadcast-update": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-5.1.4.tgz", + "integrity": "sha512-HTyTWkqXvHRuqY73XrwvXPud/FN6x3ROzkfFPsRjtw/kGZuZkPzfeH531qdUGfhtwjmtO/ZzXcWErqVzJNdXaA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-build": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-5.1.4.tgz", + "integrity": "sha512-xUcZn6SYU8usjOlfLb9Y2/f86Gdo+fy1fXgH8tJHjxgpo53VVsqRX0lUDw8/JuyzNmXuo8vXX14pXX2oIm9Bow==", + "requires": { + "@babel/core": "^7.8.4", + "@babel/preset-env": "^7.8.4", + "@babel/runtime": "^7.8.4", + "@hapi/joi": "^15.1.0", + "@rollup/plugin-node-resolve": "^7.1.1", + "@rollup/plugin-replace": "^2.3.1", + "@surma/rollup-plugin-off-main-thread": "^1.1.1", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^8.1.0", + "glob": "^7.1.6", + "lodash.template": "^4.5.0", + "pretty-bytes": "^5.3.0", + "rollup": "^1.31.1", + "rollup-plugin-babel": "^4.3.3", + "rollup-plugin-terser": "^5.3.1", + "source-map": "^0.7.3", + "source-map-url": "^0.4.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "tempy": "^0.3.0", + "upath": "^1.2.0", + "workbox-background-sync": "^5.1.4", + "workbox-broadcast-update": "^5.1.4", + "workbox-cacheable-response": "^5.1.4", + "workbox-core": "^5.1.4", + "workbox-expiration": "^5.1.4", + "workbox-google-analytics": "^5.1.4", + "workbox-navigation-preload": "^5.1.4", + "workbox-precaching": "^5.1.4", + "workbox-range-requests": "^5.1.4", + "workbox-routing": "^5.1.4", + "workbox-strategies": "^5.1.4", + "workbox-streams": "^5.1.4", + "workbox-sw": "^5.1.4", + "workbox-window": "^5.1.4" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, + "workbox-cacheable-response": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-5.1.4.tgz", + "integrity": "sha512-0bfvMZs0Of1S5cdswfQK0BXt6ulU5kVD4lwer2CeI+03czHprXR3V4Y8lPTooamn7eHP8Iywi5QjyAMjw0qauA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-core": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-5.1.4.tgz", + "integrity": "sha512-+4iRQan/1D8I81nR2L5vcbaaFskZC2CL17TLbvWVzQ4qiF/ytOGF6XeV54pVxAvKUtkLANhk8TyIUMtiMw2oDg==" + }, + "workbox-expiration": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-5.1.4.tgz", + "integrity": "sha512-oDO/5iC65h2Eq7jctAv858W2+CeRW5e0jZBMNRXpzp0ZPvuT6GblUiHnAsC5W5lANs1QS9atVOm4ifrBiYY7AQ==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-google-analytics": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz", + "integrity": "sha512-0IFhKoEVrreHpKgcOoddV+oIaVXBFKXUzJVBI+nb0bxmcwYuZMdteBTp8AEDJacENtc9xbR0wa9RDCnYsCDLjA==", + "requires": { + "workbox-background-sync": "^5.1.4", + "workbox-core": "^5.1.4", + "workbox-routing": "^5.1.4", + "workbox-strategies": "^5.1.4" + } + }, + "workbox-navigation-preload": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-5.1.4.tgz", + "integrity": "sha512-Wf03osvK0wTflAfKXba//QmWC5BIaIZARU03JIhAEO2wSB2BDROWI8Q/zmianf54kdV7e1eLaIEZhth4K4MyfQ==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-precaching": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-5.1.4.tgz", + "integrity": "sha512-gCIFrBXmVQLFwvAzuGLCmkUYGVhBb7D1k/IL7pUJUO5xacjLcFUaLnnsoVepBGAiKw34HU1y/YuqvTKim9qAZA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-range-requests": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-5.1.4.tgz", + "integrity": "sha512-1HSujLjgTeoxHrMR2muDW2dKdxqCGMc1KbeyGcmjZZAizJTFwu7CWLDmLv6O1ceWYrhfuLFJO+umYMddk2XMhw==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-routing": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-5.1.4.tgz", + "integrity": "sha512-8ljknRfqE1vEQtnMtzfksL+UXO822jJlHTIR7+BtJuxQ17+WPZfsHqvk1ynR/v0EHik4x2+826Hkwpgh4GKDCw==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-strategies": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-5.1.4.tgz", + "integrity": "sha512-VVS57LpaJTdjW3RgZvPwX0NlhNmscR7OQ9bP+N/34cYMDzXLyA6kqWffP6QKXSkca1OFo/v6v7hW7zrrguo6EA==", + "requires": { + "workbox-core": "^5.1.4", + "workbox-routing": "^5.1.4" + } + }, + "workbox-streams": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-5.1.4.tgz", + "integrity": "sha512-xU8yuF1hI/XcVhJUAfbQLa1guQUhdLMPQJkdT0kn6HP5CwiPOGiXnSFq80rAG4b1kJUChQQIGPrq439FQUNVrw==", + "requires": { + "workbox-core": "^5.1.4", + "workbox-routing": "^5.1.4" + } + }, + "workbox-sw": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-5.1.4.tgz", + "integrity": "sha512-9xKnKw95aXwSNc8kk8gki4HU0g0W6KXu+xks7wFuC7h0sembFnTrKtckqZxbSod41TDaGh+gWUA5IRXrL0ECRA==" + }, + "workbox-webpack-plugin": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.4.tgz", + "integrity": "sha512-PZafF4HpugZndqISi3rZ4ZK4A4DxO8rAqt2FwRptgsDx7NF8TVKP86/huHquUsRjMGQllsNdn4FNl8CD/UvKmQ==", + "requires": { + "@babel/runtime": "^7.5.5", + "fast-json-stable-stringify": "^2.0.0", + "source-map-url": "^0.4.0", + "upath": "^1.1.2", + "webpack-sources": "^1.3.0", + "workbox-build": "^5.1.4" + } + }, + "workbox-window": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-5.1.4.tgz", + "integrity": "sha512-vXQtgTeMCUq/4pBWMfQX8Ee7N2wVC4Q7XYFqLnfbXJ2hqew/cU1uMTD2KqGEgEpE4/30luxIxgE+LkIa8glBYw==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "requires": { + "microevent.ts": "~0.1.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", + "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==" + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/react/package.json b/react/package.json new file mode 100644 index 0000000..c86e3cf --- /dev/null +++ b/react/package.json @@ -0,0 +1,45 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "dependencies": { + "@material-ui/core": "^4.11.4", + "@material-ui/icons": "^4.11.2", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^11.2.7", + "@testing-library/user-event": "^12.8.3", + "@types/jest": "^26.0.23", + "@types/node": "^12.20.15", + "@types/react": "^17.0.11", + "@types/react-dom": "^17.0.8", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-scripts": "4.0.3", + "typescript": "^4.3.4", + "web-vitals": "^1.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "BUILD_PATH='../../build/react/src/build' react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/react/public/favicon.ico b/react/public/favicon.ico new file mode 100644 index 0000000..68428f3 Binary files /dev/null and b/react/public/favicon.ico differ diff --git a/react/public/img/cx_mono.svg b/react/public/img/cx_mono.svg new file mode 100644 index 0000000..a0f855c --- /dev/null +++ b/react/public/img/cx_mono.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/react/public/img/cx_stereo.svg b/react/public/img/cx_stereo.svg new file mode 100644 index 0000000..7fa2182 --- /dev/null +++ b/react/public/img/cx_stereo.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/react/public/img/delete_outline_black_24dp.svg b/react/public/img/delete_outline_black_24dp.svg new file mode 100644 index 0000000..51171f9 --- /dev/null +++ b/react/public/img/delete_outline_black_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/public/img/drive_file_rename_outline_black_24dp.svg b/react/public/img/drive_file_rename_outline_black_24dp.svg new file mode 100644 index 0000000..c95c5b3 --- /dev/null +++ b/react/public/img/drive_file_rename_outline_black_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/public/img/edit_banks.svg b/react/public/img/edit_banks.svg new file mode 100644 index 0000000..7d7be94 --- /dev/null +++ b/react/public/img/edit_banks.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/react/public/img/file_download_black_24dp.svg b/react/public/img/file_download_black_24dp.svg new file mode 100644 index 0000000..efc0c46 --- /dev/null +++ b/react/public/img/file_download_black_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/public/img/file_upload_black_24dp.svg b/react/public/img/file_upload_black_24dp.svg new file mode 100644 index 0000000..1ed3f1c --- /dev/null +++ b/react/public/img/file_upload_black_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/public/img/fx_amplifier.svg b/react/public/img/fx_amplifier.svg new file mode 100644 index 0000000..14fea41 --- /dev/null +++ b/react/public/img/fx_amplifier.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/react/public/img/fx_analyzer.svg b/react/public/img/fx_analyzer.svg new file mode 100644 index 0000000..54be993 --- /dev/null +++ b/react/public/img/fx_analyzer.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/react/public/img/fx_chorus.svg b/react/public/img/fx_chorus.svg new file mode 100644 index 0000000..301a39f --- /dev/null +++ b/react/public/img/fx_chorus.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_compressor.svg b/react/public/img/fx_compressor.svg new file mode 100644 index 0000000..f6d7029 --- /dev/null +++ b/react/public/img/fx_compressor.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_constant.svg b/react/public/img/fx_constant.svg new file mode 100644 index 0000000..321a890 --- /dev/null +++ b/react/public/img/fx_constant.svg @@ -0,0 +1,28 @@ + + + + + + + fx + + k + + + + + diff --git a/react/public/img/fx_converter.svg b/react/public/img/fx_converter.svg new file mode 100644 index 0000000..ade942c --- /dev/null +++ b/react/public/img/fx_converter.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_delay.svg b/react/public/img/fx_delay.svg new file mode 100644 index 0000000..b5e29ca --- /dev/null +++ b/react/public/img/fx_delay.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_dial.svg b/react/public/img/fx_dial.svg new file mode 100644 index 0000000..4152f63 --- /dev/null +++ b/react/public/img/fx_dial.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/react/public/img/fx_distortion.svg b/react/public/img/fx_distortion.svg new file mode 100644 index 0000000..1ad8b16 --- /dev/null +++ b/react/public/img/fx_distortion.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_empty.svg b/react/public/img/fx_empty.svg new file mode 100644 index 0000000..e6f1eb5 --- /dev/null +++ b/react/public/img/fx_empty.svg @@ -0,0 +1,6 @@ + + + + + diff --git a/react/public/img/fx_eq.svg b/react/public/img/fx_eq.svg new file mode 100644 index 0000000..61d6873 --- /dev/null +++ b/react/public/img/fx_eq.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_filter.svg b/react/public/img/fx_filter.svg new file mode 100644 index 0000000..e294879 --- /dev/null +++ b/react/public/img/fx_filter.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_flanger.svg b/react/public/img/fx_flanger.svg new file mode 100644 index 0000000..cf33dd9 --- /dev/null +++ b/react/public/img/fx_flanger.svg @@ -0,0 +1,72 @@ + + + + + + + + + diff --git a/react/public/img/fx_flanger2.svg b/react/public/img/fx_flanger2.svg new file mode 100644 index 0000000..ffed761 --- /dev/null +++ b/react/public/img/fx_flanger2.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_function.svg b/react/public/img/fx_function.svg new file mode 100644 index 0000000..fb59658 --- /dev/null +++ b/react/public/img/fx_function.svg @@ -0,0 +1,41 @@ + + + + + + + + fx + + + + + diff --git a/react/public/img/fx_gate.svg b/react/public/img/fx_gate.svg new file mode 100644 index 0000000..8f2462a --- /dev/null +++ b/react/public/img/fx_gate.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_generator.svg b/react/public/img/fx_generator.svg new file mode 100644 index 0000000..b77ef00 --- /dev/null +++ b/react/public/img/fx_generator.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + diff --git a/react/public/img/fx_instrument.svg b/react/public/img/fx_instrument.svg new file mode 100644 index 0000000..7627d61 --- /dev/null +++ b/react/public/img/fx_instrument.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_limiter.svg b/react/public/img/fx_limiter.svg new file mode 100644 index 0000000..2c465c7 --- /dev/null +++ b/react/public/img/fx_limiter.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/react/public/img/fx_lr.svg b/react/public/img/fx_lr.svg new file mode 100644 index 0000000..6f178d2 --- /dev/null +++ b/react/public/img/fx_lr.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_mixer.svg b/react/public/img/fx_mixer.svg new file mode 100644 index 0000000..891fd3b --- /dev/null +++ b/react/public/img/fx_mixer.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_modulator.svg b/react/public/img/fx_modulator.svg new file mode 100644 index 0000000..f1bba64 --- /dev/null +++ b/react/public/img/fx_modulator.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_oscillator.svg b/react/public/img/fx_oscillator.svg new file mode 100644 index 0000000..b034041 --- /dev/null +++ b/react/public/img/fx_oscillator.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_phaser.svg b/react/public/img/fx_phaser.svg new file mode 100644 index 0000000..414b1e2 --- /dev/null +++ b/react/public/img/fx_phaser.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_pitch.svg b/react/public/img/fx_pitch.svg new file mode 100644 index 0000000..88b9517 --- /dev/null +++ b/react/public/img/fx_pitch.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_plugin.svg b/react/public/img/fx_plugin.svg new file mode 100644 index 0000000..dc524a1 --- /dev/null +++ b/react/public/img/fx_plugin.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_reverb.svg b/react/public/img/fx_reverb.svg new file mode 100644 index 0000000..55f836f --- /dev/null +++ b/react/public/img/fx_reverb.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_simulator.svg b/react/public/img/fx_simulator.svg new file mode 100644 index 0000000..5cfd98c --- /dev/null +++ b/react/public/img/fx_simulator.svg @@ -0,0 +1,27 @@ + + + + + + + 0 + + 1 + 0 + 1 + + + + + + + + + diff --git a/react/public/img/fx_spatial.svg b/react/public/img/fx_spatial.svg new file mode 100644 index 0000000..ae27920 --- /dev/null +++ b/react/public/img/fx_spatial.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_spectral.svg b/react/public/img/fx_spectral.svg new file mode 100644 index 0000000..dadd1a1 --- /dev/null +++ b/react/public/img/fx_spectral.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/react/public/img/fx_split_a.svg b/react/public/img/fx_split_a.svg new file mode 100644 index 0000000..8dc208c --- /dev/null +++ b/react/public/img/fx_split_a.svg @@ -0,0 +1,18 @@ + + + + + + + A + + + + + + + + diff --git a/react/public/img/fx_split_b.svg b/react/public/img/fx_split_b.svg new file mode 100644 index 0000000..ddebee8 --- /dev/null +++ b/react/public/img/fx_split_b.svg @@ -0,0 +1,23 @@ + + + + + + + B + + + + + + + + + diff --git a/react/public/img/fx_terminal.svg b/react/public/img/fx_terminal.svg new file mode 100644 index 0000000..b2f746a --- /dev/null +++ b/react/public/img/fx_terminal.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/react/public/img/fx_utility.svg b/react/public/img/fx_utility.svg new file mode 100644 index 0000000..f7b40b8 --- /dev/null +++ b/react/public/img/fx_utility.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/react/public/img/help_outline_black_24dp.svg b/react/public/img/help_outline_black_24dp.svg new file mode 100644 index 0000000..44e29cd --- /dev/null +++ b/react/public/img/help_outline_black_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/public/img/ic_bank.svg b/react/public/img/ic_bank.svg new file mode 100644 index 0000000..64a6601 --- /dev/null +++ b/react/public/img/ic_bank.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/react/public/img/ic_drawer.svg b/react/public/img/ic_drawer.svg new file mode 100644 index 0000000..d2b51d3 --- /dev/null +++ b/react/public/img/ic_drawer.svg @@ -0,0 +1,11577 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + πpedal + + + + + + + + + + diff --git a/react/public/img/ic_logo.svg b/react/public/img/ic_logo.svg new file mode 100644 index 0000000..1f7e03c --- /dev/null +++ b/react/public/img/ic_logo.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + diff --git a/react/public/img/ic_midi.svg b/react/public/img/ic_midi.svg new file mode 100644 index 0000000..f8a6f7f --- /dev/null +++ b/react/public/img/ic_midi.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/react/public/img/ic_pluginpreset.svg b/react/public/img/ic_pluginpreset.svg new file mode 100644 index 0000000..10e261a --- /dev/null +++ b/react/public/img/ic_pluginpreset.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/react/public/img/ic_presets.svg b/react/public/img/ic_presets.svg new file mode 100644 index 0000000..5f3d7d5 --- /dev/null +++ b/react/public/img/ic_presets.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/react/public/img/old_delete_outline_black_24dp.svg b/react/public/img/old_delete_outline_black_24dp.svg new file mode 100644 index 0000000..24f7b41 --- /dev/null +++ b/react/public/img/old_delete_outline_black_24dp.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/react/public/img/old_delete_outline_white_24dp.svg b/react/public/img/old_delete_outline_white_24dp.svg new file mode 100644 index 0000000..bf14a7b --- /dev/null +++ b/react/public/img/old_delete_outline_white_24dp.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/react/public/img/save_bank_as.svg b/react/public/img/save_bank_as.svg new file mode 100644 index 0000000..480d0a0 --- /dev/null +++ b/react/public/img/save_bank_as.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/react/public/img/settings_black_24dp.svg b/react/public/img/settings_black_24dp.svg new file mode 100644 index 0000000..4165162 --- /dev/null +++ b/react/public/img/settings_black_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/public/index.html b/react/public/index.html new file mode 100644 index 0000000..efebeed --- /dev/null +++ b/react/public/index.html @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + PiPedal + + + +
+ + + diff --git a/react/public/logo192.png b/react/public/logo192.png new file mode 100644 index 0000000..b73484f Binary files /dev/null and b/react/public/logo192.png differ diff --git a/react/public/logo192x.png b/react/public/logo192x.png new file mode 100644 index 0000000..d483c7b Binary files /dev/null and b/react/public/logo192x.png differ diff --git a/react/public/logo512.png b/react/public/logo512.png new file mode 100644 index 0000000..696e0f1 Binary files /dev/null and b/react/public/logo512.png differ diff --git a/react/public/manifest.json b/react/public/manifest.json new file mode 100644 index 0000000..a2d368b --- /dev/null +++ b/react/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "PiPedal", + "name": "PiPedal", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/react/public/robots.txt b/react/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/react/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/react/public/sample_lv2_plugins.json b/react/public/sample_lv2_plugins.json new file mode 100644 index 0000000..da7c169 --- /dev/null +++ b/react/public/sample_lv2_plugins.json @@ -0,0 +1,15199 @@ +[ + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_aclipper_#_aclipper_", + "name": "GxRat", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": -20, + "max_value": 12, + "default_value": -2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_alembic#alembic", + "name": "Gx Alembic", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nBased on simple Alembic F-2B vstudio preamp\n2 sectionos of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "input", + "name": "Input", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "bass", + "name": "Bass", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "middle", + "name": "Middle", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "treble", + "name": "Treble", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "volume", + "name": "Volume", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_amp#GUITARIX", + "name": "GxAmplifier-X", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\nThis plugin is the combination of guitarix's head, tonestack and cabinet, which, in that order, composes the signal path. In the tube-amp part, \"PreGain\" corresponds to the gain used at the amp input, \"Drive\" controls the power amp gain, \"Distortion\" is a blend between clean and distorted sound (lower boundary is all clean, upper boundary all distorted) and \"MasterGain\" controls the output gain. Mainly, the responsible for the signal distortion are \"PreGain\" and \"Drive\" parameters. Besides that, there is a list of possible valve combinations so you can vary your distortion.\n\nAt the Tonestack part, we find a basic equalization set (\"Bass\", \"Middle\", \"Treble\" and \"Presence\") and a list of tone-responses from a few well-known amps, you can check this list in the link at the end of this description (there might be some version differences).\n\nFinally, at the Cabinet path, we have \"Cabinet\", which corresponds to another output gain, it doesn't distort the signal so it can be used as a Master output and there's another list, containing a virtual sound of the cabinet of speakers selected (more details in the link below).\n\nBased on: \nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=EnhancedUI\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Tonestack\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Cabinet_Impulse_Response_convolution\n", + "ports": [ + { + "port_index": 0, + "symbol": "MasterGain", + "name": "MasterGain", + "min_value": -20, + "max_value": 20, + "default_value": -15, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "PreGain", + "name": "PreGain", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "Distortion", + "name": "Distortion", + "min_value": 1, + "max_value": 100, + "default_value": 20, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "Drive", + "name": "Drive", + "min_value": 0.00999999978, + "max_value": 1, + "default_value": 0.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "Middle", + "name": "Middle", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Bass", + "name": "Bass", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "Treble", + "name": "Treble", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "Cabinet", + "name": "Cabinet", + "min_value": 1, + "max_value": 20, + "default_value": 10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "Presence", + "name": "Presence", + "min_value": 1, + "max_value": 10, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "model", + "name": "Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 10, + "label": "pre 12ax7/ master 6V6" + }, + { + "value": 3, + "label": "6DJ8" + }, + { + "value": 2, + "label": "12AT7" + }, + { + "value": 4, + "label": "6C16" + }, + { + "value": 1, + "label": "12AU7" + }, + { + "value": 0, + "label": "12ax7" + }, + { + "value": 5, + "label": "6V6" + }, + { + "value": 11, + "label": "pre 12AU7/ master 6V6" + }, + { + "value": 6, + "label": "12ax7 feedback" + }, + { + "value": 13, + "label": "pre 6DJ8/ master 6V6" + }, + { + "value": 14, + "label": "pre 12ax7/ push-pull 6V6" + }, + { + "value": 15, + "label": "pre 12AU7/ push-pull 6V6" + }, + { + "value": 16, + "label": "pre 12AT7/ push pull 6V6" + }, + { + "value": 17, + "label": "pre 6DJ8/ push-pull 6V6" + }, + { + "value": 12, + "label": "pre 12AT7/ master 6V6" + }, + { + "value": 7, + "label": "12AU7 feedback" + }, + { + "value": 8, + "label": "12AT7 feedback" + }, + { + "value": 9, + "label": "6DJ8 feedback" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "t_model", + "name": "Tonestack Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 6, + "label": "M-Lead Style" + }, + { + "value": 5, + "label": "JCM-2000 Style" + }, + { + "value": 3, + "label": "Princeton Style" + }, + { + "value": 4, + "label": "JCM-800 Style" + }, + { + "value": 15, + "label": "Roland Style" + }, + { + "value": 2, + "label": "Twin Reverb Style" + }, + { + "value": 0, + "label": "default" + }, + { + "value": 1, + "label": "Bassman Style" + }, + { + "value": 17, + "label": "Rev.Rocket Style" + }, + { + "value": 16, + "label": "Ampeg Style" + }, + { + "value": 7, + "label": "M2199 Style" + }, + { + "value": 8, + "label": "AC-30 Style" + }, + { + "value": 11, + "label": "JTM-45 Style" + }, + { + "value": 9, + "label": "Mesa Boogie Style" + }, + { + "value": 10, + "label": "SOL 100 Style" + }, + { + "value": 14, + "label": "Ibanez Style" + }, + { + "value": 13, + "label": "Peavey Style" + }, + { + "value": 12, + "label": "AC-15 Style" + }, + { + "value": 18, + "label": "MIG 100 H Style" + }, + { + "value": 19, + "label": "Triple Giant Style" + }, + { + "value": 20, + "label": "Trio Preamp Style" + }, + { + "value": 21, + "label": "Hughes&Kettner Style" + }, + { + "value": 22, + "label": "Fender Junior Style" + }, + { + "value": 23, + "label": "Fender Style" + }, + { + "value": 24, + "label": "Fender Deville Style" + }, + { + "value": 25, + "label": "Gibsen Style" + }, + { + "value": 26, + "label": "Off" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "c_model", + "name": "Cab Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 6, + "label": "Twin Style" + }, + { + "value": 4, + "label": "2x10" + }, + { + "value": 5, + "label": "HighGain Style" + }, + { + "value": 3, + "label": "4x10" + }, + { + "value": 2, + "label": "1x12" + }, + { + "value": 1, + "label": "2x12" + }, + { + "value": 0, + "label": "4x12" + }, + { + "value": 7, + "label": "Bassman Style" + }, + { + "value": 16, + "label": "Charisma" + }, + { + "value": 18, + "label": "Off" + }, + { + "value": 17, + "label": "1x8" + }, + { + "value": 14, + "label": "Briliant" + }, + { + "value": 13, + "label": "Mesa Style" + }, + { + "value": 15, + "label": "Vitalize" + }, + { + "value": 9, + "label": "AC30 Style" + }, + { + "value": 8, + "label": "Marshall Style" + }, + { + "value": 12, + "label": "1x15" + }, + { + "value": 11, + "label": "A2 Style" + }, + { + "value": 10, + "label": "Princeton Style" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "control", + "name": "Control", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "notify", + "name": "Notify", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "SCHEDULE", + "name": "SCHEDULE", + "min_value": 0, + "max_value": 1, + "default_value": 1, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_amp_stereo#GUITARIX_ST", + "name": "GxAmplifier-Stereo-X", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\nStereo version of gx_amp.\n\nThis plugin is the combination of guitarix's head, tonestack and cabinet, which, in that order, composes the signal path. In the tube-amp part, \"PreGain\" corresponds to the gain used at the amp input, \"Drive\" controls the power amp gain, \"Distortion\" is a blend between clean and distorted sound (lower boundary is all clean, upper boundary all distorted) and \"MasterGain\" controls the output gain. Mainly, the responsible for the signal distortion are \"PreGain\" and \"Drive\" parameters. Besides that, there is a list of possible valve combinations so you can vary your distortion.\n\nAt the Tonestack part, we find a basic equalization set (\"Bass\", \"Middle\", \"Treble\" and \"Presence\") and a list of tone-responses from a few well-known amps, you can check this list in the link at the end of this description (there might be some version differences).\n\nFinally, at the Cabinet path, we have \"Cabinet\", which corresponds to another output gain, it doesn't distort the signal so it can be used as a Master output and there's another list, containing a virtual sound of the cabinet of speakers selected (more details in the link below).\n\nBased on: \nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=EnhancedUI\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Tonestack\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Cabinet_Impulse_Response_convolution\n", + "ports": [ + { + "port_index": 0, + "symbol": "MasterGain", + "name": "MasterGain", + "min_value": -20, + "max_value": 20, + "default_value": -15, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "PreGain", + "name": "PreGain", + "min_value": -20, + "max_value": 20, + "default_value": -15, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "Distortion", + "name": "Distortion", + "min_value": 1, + "max_value": 100, + "default_value": 20, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "Drive", + "name": "Drive", + "min_value": 0.00999999978, + "max_value": 1, + "default_value": 0.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "Middle", + "name": "Middle", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Bass", + "name": "Bass", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "Treble", + "name": "Treble", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "Cabinet", + "name": "Cabinet", + "min_value": 1, + "max_value": 20, + "default_value": 10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "Presence", + "name": "Presence", + "min_value": 1, + "max_value": 10, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "model", + "name": "Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 4, + "label": "6C16" + }, + { + "value": 5, + "label": "6V6" + }, + { + "value": 6, + "label": "12ax7 feedback" + }, + { + "value": 8, + "label": "12AT7 feedback" + }, + { + "value": 10, + "label": "pre 12ax7/ master 6V6" + }, + { + "value": 7, + "label": "12AU7 feedback" + }, + { + "value": 9, + "label": "6DJ8 feedback" + }, + { + "value": 14, + "label": "pre 12ax7/ push-pull 6V6" + }, + { + "value": 3, + "label": "6DJ8" + }, + { + "value": 11, + "label": "pre 12AU7/ master 6V6" + }, + { + "value": 13, + "label": "pre 6DJ8/ master 6V6" + }, + { + "value": 12, + "label": "pre 12AT7/ master 6V6" + }, + { + "value": 2, + "label": "12AT7" + }, + { + "value": 16, + "label": "pre 12AT7/ push pull 6V6" + }, + { + "value": 15, + "label": "pre 12AU7/ push-pull 6V6" + }, + { + "value": 0, + "label": "12ax7" + }, + { + "value": 17, + "label": "pre 6DJ8/ push-pull 6V6" + }, + { + "value": 1, + "label": "12AU7" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "t_model", + "name": "Tonestack Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 5, + "label": "JCM-2000 Style" + }, + { + "value": 3, + "label": "Princeton Style" + }, + { + "value": 4, + "label": "JCM-800 Style" + }, + { + "value": 17, + "label": "Rev.Rocket Style" + }, + { + "value": 2, + "label": "Twin Reverb Style" + }, + { + "value": 16, + "label": "Ampeg Style" + }, + { + "value": 0, + "label": "default" + }, + { + "value": 1, + "label": "Bassman Style" + }, + { + "value": 6, + "label": "M-Lead Style" + }, + { + "value": 7, + "label": "M2199 Style" + }, + { + "value": 15, + "label": "Roland Style" + }, + { + "value": 18, + "label": "MIG 100 H Style" + }, + { + "value": 14, + "label": "Ibanez Style" + }, + { + "value": 8, + "label": "AC-30 Style" + }, + { + "value": 10, + "label": "SOL 100 Style" + }, + { + "value": 9, + "label": "Mesa Boogie Style" + }, + { + "value": 13, + "label": "Peavey Style" + }, + { + "value": 11, + "label": "JTM-45 Style" + }, + { + "value": 12, + "label": "AC-15 Style" + }, + { + "value": 19, + "label": "Triple Giant Style" + }, + { + "value": 20, + "label": "Trio Preamp Style" + }, + { + "value": 21, + "label": "Hughes&Kettner Style" + }, + { + "value": 22, + "label": "Fender Junior Style" + }, + { + "value": 23, + "label": "Fender Style" + }, + { + "value": 24, + "label": "Fender Deville Style" + }, + { + "value": 25, + "label": "Gibsen Style" + }, + { + "value": 26, + "label": "Off" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "c_model", + "name": "Cab Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 6, + "label": "Twin Style" + }, + { + "value": 5, + "label": "HighGain Style" + }, + { + "value": 4, + "label": "2x10" + }, + { + "value": 2, + "label": "1x12" + }, + { + "value": 3, + "label": "4x10" + }, + { + "value": 0, + "label": "4x12" + }, + { + "value": 1, + "label": "2x12" + }, + { + "value": 7, + "label": "Bassman Style" + }, + { + "value": 18, + "label": "Off" + }, + { + "value": 17, + "label": "1x8" + }, + { + "value": 16, + "label": "Charisma" + }, + { + "value": 14, + "label": "Briliant" + }, + { + "value": 13, + "label": "Mesa Style" + }, + { + "value": 8, + "label": "Marshall Style" + }, + { + "value": 15, + "label": "Vitalize" + }, + { + "value": 12, + "label": "1x15" + }, + { + "value": 9, + "label": "AC30 Style" + }, + { + "value": 11, + "label": "A2 Style" + }, + { + "value": 10, + "label": "Princeton Style" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "control", + "name": "Control", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "notify", + "name": "Notify", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "SCHEDULE", + "name": "SCHEDULE", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_barkgraphiceq_#_barkgraphiceq_", + "name": "GxBarkGraphicEQ", + "plugin_class": "http://lv2plug.in/ns/lv2core#EQPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nA Graphic Equalizer with Bark frequency scale.\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "G1", + "name": "G1", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "G2", + "name": "G2", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "G3", + "name": "G3", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "G4", + "name": "G4", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "G5", + "name": "G5", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "G6", + "name": "G6", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "G7", + "name": "G7", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "G8", + "name": "G8", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "G9", + "name": "G9", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "G10", + "name": "G10", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "G11", + "name": "G11", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "G12", + "name": "G12", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "G13", + "name": "G13", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "G14", + "name": "G14", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "G15", + "name": "G15", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "G16", + "name": "G16", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "G17", + "name": "G17", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "G18", + "name": "G18", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "G19", + "name": "G19", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "G20", + "name": "G20", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "G21", + "name": "G21", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "G22", + "name": "G22", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 22, + "symbol": "G23", + "name": "G23", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 23, + "symbol": "G24", + "name": "G24", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 24, + "symbol": "V1", + "name": "V1", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 25, + "symbol": "V2", + "name": "V2", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 26, + "symbol": "V3", + "name": "V3", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 27, + "symbol": "V4", + "name": "V4", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 28, + "symbol": "V5", + "name": "V5", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 29, + "symbol": "V6", + "name": "V6", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 30, + "symbol": "V7", + "name": "V7", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 31, + "symbol": "V8", + "name": "V8", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 32, + "symbol": "V9", + "name": "V9", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 33, + "symbol": "V10", + "name": "V10", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 34, + "symbol": "V11", + "name": "V11", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 35, + "symbol": "V12", + "name": "V12", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 36, + "symbol": "V13", + "name": "V13", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 37, + "symbol": "V14", + "name": "V14", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 38, + "symbol": "V15", + "name": "V15", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 39, + "symbol": "V16", + "name": "V16", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 40, + "symbol": "V17", + "name": "V17", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 41, + "symbol": "V18", + "name": "V18", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 42, + "symbol": "V19", + "name": "V19", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 43, + "symbol": "V20", + "name": "V20", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 44, + "symbol": "V21", + "name": "V21", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 45, + "symbol": "V22", + "name": "V22", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 46, + "symbol": "V23", + "name": "V23", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 47, + "symbol": "V24", + "name": "V24", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 48, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 49, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_bmp_#_bmp_", + "name": "GxBigMuffPi", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "SUSTAIN", + "name": "SUSTAIN", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_bossds1_#_bossds1_", + "name": "GxBoss DS1", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": -20, + "max_value": 12, + "default_value": -2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_cabinet#CABINET", + "name": "GxCabinet", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "CLevel", + "name": "Cabinet", + "min_value": 0.5, + "max_value": 5, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "CBass", + "name": "Bass", + "min_value": -10, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "CTreble", + "name": "Treble", + "min_value": -10, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "c_model", + "name": "Cab Model", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 7, + "label": "Bassman Style" + }, + { + "value": 6, + "label": "Twin Style" + }, + { + "value": 8, + "label": "Marshall Style" + }, + { + "value": 9, + "label": "AC30 Style" + }, + { + "value": 5, + "label": "HighGain Style" + }, + { + "value": 11, + "label": "A2 Style" + }, + { + "value": 15, + "label": "Vitalize" + }, + { + "value": 12, + "label": "1x15" + }, + { + "value": 13, + "label": "Mesa Style" + }, + { + "value": 14, + "label": "Briliant" + }, + { + "value": 10, + "label": "Princeton Style" + }, + { + "value": 16, + "label": "Charisma" + }, + { + "value": 17, + "label": "1x8" + }, + { + "value": 18, + "label": "Off" + }, + { + "value": 0, + "label": "4x12" + }, + { + "value": 1, + "label": "2x12" + }, + { + "value": 2, + "label": "1x12" + }, + { + "value": 3, + "label": "4x10" + }, + { + "value": 4, + "label": "2x10" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "control", + "name": "Control", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "notify", + "name": "Notify", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "SCHEDULE", + "name": "SCHEDULE", + "min_value": 0, + "max_value": 1, + "default_value": 1, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_chorus_stereo#_chorus_stereo", + "name": "GxChorus-Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ChorusPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"In music, a chorus effect (sometimes chorusing or chorused effect) occurs when individual sounds with roughly the same timbre and nearly (but never exactly) the same pitch converge and are perceived as one. While similar sounds coming from multiple sources can occur naturally (as in the case of a choir or string orchestra), it can also be simulated using an electronic effects unit or signal processing device.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Chorus_effect\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "level", + "name": "Level", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "delay", + "name": "Delay", + "min_value": 0, + "max_value": 0.200000003, + "default_value": 0.0199999996, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "depth", + "name": "Depth", + "min_value": 0, + "max_value": 1, + "default_value": 0.0199999996, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "freq", + "name": "Freq", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 3, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_colwah_#_colwah_", + "name": "GxWahwah", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "WAH", + "name": "WAH", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "FREQ", + "name": "FREQ", + "min_value": 24, + "max_value": 360, + "default_value": 24, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "MODE", + "name": "MODE", + "min_value": 0, + "max_value": 2, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "auto" + }, + { + "value": 2, + "label": "alien" + }, + { + "value": 0, + "label": "manual" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "MODEL", + "name": "MODEL", + "min_value": 0, + "max_value": 6, + "default_value": 0, + "scale_points": [ + { + "value": 4, + "label": "Maestro Wah" + }, + { + "value": 3, + "label": "Jen Wah" + }, + { + "value": 5, + "label": "SelmerWah" + }, + { + "value": 2, + "label": "Foxx Wah" + }, + { + "value": 0, + "label": "Colorsound Wah" + }, + { + "value": 6, + "label": "Vox Wah V847" + }, + { + "value": 1, + "label": "Dallas Wah" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "WET_DRY", + "name": "WET_DRY", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_compressor#_compressor", + "name": "GxCompressor", + "plugin_class": "http://lv2plug.in/ns/lv2core#CompressorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"Compression (or more technically Dynamic range compression) is a subtle effect primarily for electric guitar where the highest and lowest points of the sound wave are \"limited\". This boosts the volume of softer picked notes, while capping the louder ones, giving a more even level of volume. This is frequently used in country music, where fast clean passages can sound uneven unless artificially 'squashed'.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Compression_%28electric_guitar%29\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "RATIO", + "name": "RATIO", + "min_value": 1, + "max_value": 20, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "KNEE", + "name": "KNEE", + "min_value": 0, + "max_value": 20, + "default_value": 3, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "min_value": -96, + "max_value": 10, + "default_value": -20, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "RELEASE", + "name": "RELEASE", + "min_value": 0, + "max_value": 10, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "ATTACK", + "name": "ATTACK", + "min_value": 0, + "max_value": 1, + "default_value": 0.00200000009, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_cstb_#_cstb_", + "name": "GxColorSound Tonebender", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "ATTACK", + "name": "ATTACK", + "min_value": 0, + "max_value": 0.949999988, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "WET_DRY", + "name": "WET_DRY", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_delay_stereo#_delay_stereo", + "name": "GxDelay-Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nA stereo delay plugin with independent delay time and delay gain for each channel. It also has a LFO modulator and two modes: linear and pingpong.\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "mode", + "name": "Mode", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "pingpong" + }, + { + "value": 0, + "label": "linear" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "level_r", + "name": "R Level", + "min_value": -20, + "max_value": 20, + "default_value": -10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "timt_r", + "name": "R Time", + "min_value": 1, + "max_value": 5000, + "default_value": 1000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "level_l", + "name": "L Level", + "min_value": -20, + "max_value": 20, + "default_value": -10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "timt_l", + "name": "L Time", + "min_value": 1, + "max_value": 5000, + "default_value": 1000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "lfo", + "name": "LFO", + "min_value": 0.200000003, + "max_value": 5, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "link", + "name": "Link (L+R)", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_detune_#_detune_", + "name": "Gxdetune", + "plugin_class": "http://lv2plug.in/ns/lv2core#PitchPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DETUNE", + "name": "DETUNE", + "min_value": -12, + "max_value": 12, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "OCTAVE", + "name": "OCTAVE", + "min_value": 0, + "max_value": 2, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "octaveup" + }, + { + "value": 2, + "label": "octavedown" + }, + { + "value": 0, + "label": "normal" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "COMPENSATE", + "name": "COMPENSATE", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "compensate" + }, + { + "value": 0, + "label": "latency" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "LATENCY", + "name": "LATENCY", + "min_value": 0, + "max_value": 2, + "default_value": 0, + "scale_points": [ + { + "value": 2, + "label": "realtime" + }, + { + "value": 0, + "label": "highquality" + }, + { + "value": 1, + "label": "lowquality" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "WET", + "name": "WET", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "DRY", + "name": "DRY", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "LOW", + "name": "LOW", + "min_value": 0, + "max_value": 2, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "MIDDLELOW", + "name": "MIDDLELOW", + "min_value": 0, + "max_value": 2, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "MIDDLETREBLE", + "name": "MIDDLETREBLE", + "min_value": 0, + "max_value": 2, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "TREBLE", + "name": "TREBLE", + "min_value": 0, + "max_value": 2, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "latency", + "name": "latency (samples)", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_digital_delay_#_digital_delay_", + "name": "Gxdigital_delay", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/urid#map" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/urid#map" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "BPM", + "name": "BPM", + "min_value": 24, + "max_value": 360, + "default_value": 120, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "GAIN", + "name": "GAIN", + "min_value": 0, + "max_value": 120, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "HIGHPASS", + "name": "HIGHPASS", + "min_value": 20, + "max_value": 20000, + "default_value": 120, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "HOWPASS", + "name": "HOWPASS", + "min_value": 20, + "max_value": 20000, + "default_value": 12000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "MODE", + "name": "MODE", + "min_value": 0, + "max_value": 3, + "default_value": 0, + "scale_points": [ + { + "value": 0, + "label": "plain" + }, + { + "value": 1, + "label": "presence" + }, + { + "value": 2, + "label": "tape" + }, + { + "value": 3, + "label": "tape2" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "NOTES", + "name": "NOTES", + "min_value": 1, + "max_value": 18, + "default_value": 5, + "scale_points": [ + { + "value": 4, + "label": "Dotted1/4note" + }, + { + "value": 1, + "label": "Dotted1/2note" + }, + { + "value": 2, + "label": "1/2note" + }, + { + "value": 3, + "label": "1/2notetriplets" + }, + { + "value": 7, + "label": "Dotted1/8note" + }, + { + "value": 6, + "label": "1/4notetriplets" + }, + { + "value": 5, + "label": "1/4note" + }, + { + "value": 8, + "label": "1/8note" + }, + { + "value": 9, + "label": "1/8notetriplets" + }, + { + "value": 10, + "label": "Dotted1/16note" + }, + { + "value": 11, + "label": "1/16note" + }, + { + "value": 12, + "label": "1/16notetriplets" + }, + { + "value": 13, + "label": "Dotted1/32note" + }, + { + "value": 14, + "label": "1/32note" + }, + { + "value": 15, + "label": "1/32notetriplets" + }, + { + "value": 16, + "label": "Dotted1/64note" + }, + { + "value": 17, + "label": "1/64note" + }, + { + "value": 18, + "label": "1/64notetriplets" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "DD_CONTROL", + "name": "DD_CONTROL", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "DD_NOTIFY", + "name": "DD_NOTIFY", + "min_value": 24, + "max_value": 360, + "default_value": 120, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "SYNC", + "name": "SYNC", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_digital_delay_st_#_digital_delay_st_", + "name": "Gxdigital_delay_st", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "BPM", + "name": "BPM", + "min_value": 24, + "max_value": 360, + "default_value": 120, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "GAIN", + "name": "GAIN", + "min_value": 0, + "max_value": 120, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "HIGHPASS", + "name": "HIGHPASS", + "min_value": 20, + "max_value": 20000, + "default_value": 120, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "HOWPASS", + "name": "HOWPASS", + "min_value": 20, + "max_value": 20000, + "default_value": 12000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "MODE", + "name": "MODE", + "min_value": 0, + "max_value": 3, + "default_value": 0, + "scale_points": [ + { + "value": 0, + "label": "plain" + }, + { + "value": 1, + "label": "presence" + }, + { + "value": 3, + "label": "tape2" + }, + { + "value": 2, + "label": "tape" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "NOTES", + "name": "NOTES", + "min_value": 1, + "max_value": 18, + "default_value": 5, + "scale_points": [ + { + "value": 4, + "label": "Dotted1/4note" + }, + { + "value": 1, + "label": "Dotted1/2note" + }, + { + "value": 5, + "label": "1/4note" + }, + { + "value": 3, + "label": "1/2notetriplets" + }, + { + "value": 2, + "label": "1/2note" + }, + { + "value": 8, + "label": "1/8note" + }, + { + "value": 7, + "label": "Dotted1/8note" + }, + { + "value": 6, + "label": "1/4notetriplets" + }, + { + "value": 9, + "label": "1/8notetriplets" + }, + { + "value": 10, + "label": "Dotted1/16note" + }, + { + "value": 11, + "label": "1/16note" + }, + { + "value": 12, + "label": "1/16notetriplets" + }, + { + "value": 13, + "label": "Dotted1/32note" + }, + { + "value": 14, + "label": "1/32note" + }, + { + "value": 15, + "label": "1/32notetriplets" + }, + { + "value": 16, + "label": "Dotted1/64note" + }, + { + "value": 18, + "label": "1/64notetriplets" + }, + { + "value": 17, + "label": "1/64note" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_duck_delay_#_duck_delay_", + "name": "Gxduck_delay", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nThe delayed signal added to output dependent of input signal amplitude. \nIf the input signal is high. The delayed signall turned off, and vise versa.\nThe switching controlled by envelope follower\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "AMOUNT", + "name": "AMOUNT", + "min_value": 0, + "max_value": 56, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "ATTACK", + "name": "ATTACK", + "min_value": 0.0500000007, + "max_value": 0.5, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "RELESE", + "name": "RELESE", + "min_value": 0.0500000007, + "max_value": 2, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "TIME", + "name": "TIME", + "min_value": 1, + "max_value": 2000, + "default_value": 500, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_duck_delay_st_#_duck_delay_st_", + "name": "Gxduck_delay_st", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nThe delayed signal added to output dependent of input signal amplitude. \nIf the input signal is high. The delayed signall turned off, and vise versa.\nThe switching controlled by envelope follower\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "AMOUNT", + "name": "AMOUNT", + "min_value": 0, + "max_value": 56, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "ATTACK", + "name": "ATTACK", + "min_value": 0.0500000007, + "max_value": 0.5, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "COLORATION", + "name": "COLORATION", + "min_value": -1, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "EFFECT", + "name": "EFFECT", + "min_value": -16, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "PINGPONG", + "name": "PINGPONG", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "RELEASE", + "name": "RELEASE", + "min_value": 0.0500000007, + "max_value": 2, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "TIME", + "name": "TIME", + "min_value": 1, + "max_value": 2000, + "default_value": 500, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_echo_stereo#_echo_stereo", + "name": "GxEcho-Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nA stereo echo plugin with independent delay time and delay volume for each channel. It also has a LFO modulator and two modes: linear and pingpong.\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "mode", + "name": "Mode", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "pingpong" + }, + { + "value": 0, + "label": "linear" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "level_r", + "name": "R Level", + "min_value": 0, + "max_value": 100, + "default_value": 30, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "timt_r", + "name": "R Time", + "min_value": 1, + "max_value": 2000, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "level_l", + "name": "L Level", + "min_value": 0, + "max_value": 100, + "default_value": 30, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "timt_l", + "name": "L Time", + "min_value": 1, + "max_value": 2000, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "lfo", + "name": "LFO", + "min_value": 0.200000003, + "max_value": 5, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "link", + "name": "Link (L+R)", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_expander#_expander", + "name": "GxExpander", + "plugin_class": "http://lv2plug.in/ns/lv2core#ExpanderPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"The expander is a compressor in reverse. There are two types of expander. In some, signals above the threshold remain at unity gain whereas signals below the threshold are reduced in gain, whereas in others the signal above the threshold also has the gain increased. Therefore you can use an expander as a noise reduction unit. Set the threshold to be just below the level of the player when playing. When the player stops the signal will fall below this threshold and the signal is reduced in gain thus reducing the noise or spill.\"\n\n*Unofficial documentation\n\nsource: http://www.sae.edu/reference_material/audio/pages/Compression.htm\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "RATIO", + "name": "RATIO", + "min_value": 1, + "max_value": 20, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "KNEE", + "name": "KNEE", + "min_value": 0, + "max_value": 20, + "default_value": 3, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "min_value": -96, + "max_value": 10, + "default_value": -40, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "RELEASE", + "name": "RELEASE", + "min_value": 0, + "max_value": 10, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "ATTACK", + "name": "ATTACK", + "min_value": 0, + "max_value": 1, + "default_value": 0.00100000005, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_flanger#_flanger", + "name": "GxFlanger", + "plugin_class": "http://lv2plug.in/ns/lv2core#FlangerPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"Flanging /\u02C8fl\u00E6nd\u0292\u02EA\u01CB/ is an audio effect produced by mixing two identical signals together, one signal delayed by a small and gradually changing period, usually smaller than 20 milliseconds. This produces a swept comb filter effect: peaks and notches are produced in the resulting frequency spectrum, related to each other in a linear harmonic series. Varying the time delay causes these to sweep up and down the frequency spectrum. A flanger is an effects unit that creates this effect.\n\nPart of the output signal is usually fed back to the input (a \"re-circulating delay line\"), producing a resonance effect which further enhances the intensity of the peaks and troughs. The phase of the fed-back signal is sometimes inverted, producing another variation on the flanging sound.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Flanging\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "depth", + "name": "DEPTH", + "min_value": 0, + "max_value": 5, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "width", + "name": "WIDTH", + "min_value": 0, + "max_value": 10, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "freq", + "name": "FREQ", + "min_value": 0.0500000007, + "max_value": 10, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "feedback", + "name": "FEEDBACK", + "min_value": -0.99000001, + "max_value": 0.99000001, + "default_value": -0.707000017, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "dry_wet", + "name": "WET", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "mix", + "name": "MIX", + "min_value": -1, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fumaster_#_fumaster_", + "name": "GxFuzzMaster", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "WET_DRY", + "name": "WET_DRY", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fuzz_#fuzz_", + "name": "GxFuzz", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\nA Fuzz Effect\n\n*Unofficial documentation\n", + "ports": [ + { + "port_index": 0, + "symbol": "INPUT", + "name": "INPUT", + "min_value": -20, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "OUTPUT", + "name": "OUTPUT", + "min_value": 50, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": -3, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "V1", + "name": "V1", + "min_value": 0, + "max_value": 1.5, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fuzzface_#_fuzzface_", + "name": "GxFuzzFaceJH2", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "FUZZ", + "name": "FUZZ", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fuzzfacefm_#_fuzzfacefm_", + "name": "GxFuzzFaceFuller", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "FUZZ", + "name": "FUZZ", + "min_value": 0, + "max_value": 0.99000001, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "INPUT", + "name": "INPUT", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_gcb_95_#_gcb_95_", + "name": "Gxgcb_95", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": -20, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "HOTPOTZ", + "name": "WAH", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_graphiceq_#_graphiceq_", + "name": "GxGraphicEQ", + "plugin_class": "http://lv2plug.in/ns/lv2core#EQPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"In the graphic equalizer, the input signal is sent to a bank of filters. Each filter passes the portion of the signal present in its own frequency range or band. The amplitude passed by each filter is adjusted using a slide control to boost or cut frequency components passed by that filter. The vertical position of each slider thus indicates the gain applied at that frequency band, so that the knobs resemble a graph of the equalizer's response plotted versus frequency.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Equalization_%28audio%29#Graphic_equalizer\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "G10", + "name": "G10", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "G11", + "name": "G11", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "G1", + "name": "G1", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "G2", + "name": "G2", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "G3", + "name": "G3", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "G4", + "name": "G4", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "G5", + "name": "G5", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "G6", + "name": "G6", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "G7", + "name": "G7", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "G8", + "name": "G8", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "G9", + "name": "G9", + "min_value": -30, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "V10", + "name": "V10", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "V11", + "name": "V11", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "V1", + "name": "V1", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "V2", + "name": "V2", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "V3", + "name": "V3", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "V4", + "name": "V4", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "V5", + "name": "V5", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "V6", + "name": "V6", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "V7", + "name": "V7", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "V8", + "name": "V8", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "V9", + "name": "V9", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 22, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 23, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_hfb_#_hfb_", + "name": "GxHF_Brightener", + "plugin_class": "http://lv2plug.in/ns/lv2core#EQPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "INTENSITY", + "name": "INTENSITY", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_hogsfoot_#_hogsfoot_", + "name": "GxHogsFoot", + "plugin_class": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "WET_DRY", + "name": "WET_DRY", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_hornet_#_hornet_", + "name": "GxHornet", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "FUZZ", + "name": "FUZZ", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "SUSTAIN", + "name": "SUSTAIN", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_jcm800pre_#_jcm800pre_", + "name": "Gxjcm800pre", + "plugin_class": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "P6v", + "name": "Pre Amp", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "Middle", + "name": "Middle", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "Bass", + "name": "Bass", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Treble", + "name": "Treble", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "WET_DRY", + "name": "Presence", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "GAIN", + "name": "Master Volume", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_jcm800pre_st#_jcm800pre_st", + "name": "Gxjcm800preST", + "plugin_class": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "P6v", + "name": "Pre Amp", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Middle", + "name": "Middle", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "Bass", + "name": "Bass", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "Treble", + "name": "Treble", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "WET_DRY", + "name": "Presence", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "GAIN", + "name": "Master Volume", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_livelooper_#_livelooper_", + "name": "Gxlivelooper", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "clip1", + "name": "clip1", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "clip2", + "name": "clip2", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "clip3", + "name": "clip3", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "clip4", + "name": "clip4", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "clips1", + "name": "clips1", + "min_value": 0, + "max_value": 100, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "clips2", + "name": "clips2", + "min_value": 0, + "max_value": 100, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "clips3", + "name": "clips3", + "min_value": 0, + "max_value": 100, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "clips4", + "name": "clips4", + "min_value": 0, + "max_value": 100, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "speed1", + "name": "speed1", + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "speed2", + "name": "speed2", + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "speed3", + "name": "speed3", + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "speed4", + "name": "speed4", + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "bar1", + "name": "bar1", + "min_value": 0, + "max_value": 96, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "bar2", + "name": "bar2", + "min_value": 0, + "max_value": 96, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "bar3", + "name": "bar3", + "min_value": 0, + "max_value": 96, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "bar4", + "name": "bar4", + "min_value": 0, + "max_value": 96, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "gain", + "name": "gain", + "min_value": -20, + "max_value": 12, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "level1", + "name": "level1", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "level2", + "name": "level2", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "level3", + "name": "level3", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 22, + "symbol": "level4", + "name": "level4", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 23, + "symbol": "mix", + "name": "mix", + "min_value": 0, + "max_value": 150, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 24, + "symbol": "play1", + "name": "play1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 25, + "symbol": "play2", + "name": "play2", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 26, + "symbol": "play3", + "name": "play3", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 27, + "symbol": "play4", + "name": "play4", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 28, + "symbol": "rplay1", + "name": "rplay1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 29, + "symbol": "rplay2", + "name": "rplay2", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 30, + "symbol": "rplay3", + "name": "rplay3", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 31, + "symbol": "rplay4", + "name": "rplay4", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 32, + "symbol": "playh1", + "name": "playh1", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 33, + "symbol": "playh2", + "name": "playh2", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 34, + "symbol": "playh3", + "name": "playh3", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 35, + "symbol": "playh4", + "name": "playh4", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 36, + "symbol": "rec1", + "name": "rec1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 37, + "symbol": "rec2", + "name": "rec2", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 38, + "symbol": "rec3", + "name": "rec3", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 39, + "symbol": "rec4", + "name": "rec4", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 40, + "symbol": "reset1", + "name": "reset1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 41, + "symbol": "reset2", + "name": "reset2", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 42, + "symbol": "reset3", + "name": "reset3", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 43, + "symbol": "reset4", + "name": "reset4", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbcompressor_#_mbcompressor_", + "name": "GxMultiBandCompressor", + "plugin_class": "http://lv2plug.in/ns/lv2core#CompressorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"Multiband (also spelled multi-band) compressors can act differently on different frequency bands. The advantage of multiband compression over full-bandwidth (full-band, or single-band) compression is that unneeded audible gain changes or \"pumping\" in other frequency bands is not caused by changing signal levels in a single frequency band.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Dynamic_range_compression#Multiband_compression\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "MODE1", + "name": "MODE1", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + }, + { + "value": 1, + "label": "Compress" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "MODE2", + "name": "MODE2", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + }, + { + "value": 1, + "label": "Compress" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "MODE3", + "name": "MODE3", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "MODE4", + "name": "MODE4", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 3, + "label": "Mute" + }, + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "MODE5", + "name": "MODE5", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 3, + "label": "Mute" + }, + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "MAKEUP1", + "name": "MAKEUP1", + "min_value": -50, + "max_value": 50, + "default_value": 13, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "MAKEUP2", + "name": "MAKEUP2", + "min_value": -50, + "max_value": 50, + "default_value": 13, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "MAKEUP3", + "name": "MAKEUP3", + "min_value": -50, + "max_value": 50, + "default_value": 13, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "MAKEUP4", + "name": "MAKEUP4", + "min_value": -50, + "max_value": 50, + "default_value": 13, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "MAKEUP5", + "name": "MAKEUP5", + "min_value": -50, + "max_value": 50, + "default_value": 13, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "MAKEUPTHRESHOLD1", + "name": "MAKEUPTHRESHOLD1", + "min_value": 0, + "max_value": 10, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "MAKEUPTHRESHOLD2", + "name": "MAKEUPTHRESHOLD2", + "min_value": 0, + "max_value": 10, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "MAKEUPTHRESHOLD3", + "name": "MAKEUPTHRESHOLD3", + "min_value": 0, + "max_value": 10, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "MAKEUPTHRESHOLD4", + "name": "MAKEUPTHRESHOLD4", + "min_value": 0, + "max_value": 10, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "MAKEUPTHRESHOLD5", + "name": "MAKEUPTHRESHOLD5", + "min_value": 0, + "max_value": 10, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "RATIO1", + "name": "RATIO1", + "min_value": 1, + "max_value": 100, + "default_value": 13, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "RATIO2", + "name": "RATIO2", + "min_value": 1, + "max_value": 100, + "default_value": 10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "RATIO3", + "name": "RATIO3", + "min_value": 1, + "max_value": 100, + "default_value": 4, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "RATIO4", + "name": "RATIO4", + "min_value": 1, + "max_value": 100, + "default_value": 8, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "RATIO5", + "name": "RATIO5", + "min_value": 1, + "max_value": 100, + "default_value": 11, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "ATTACK1", + "name": "ATTACK1", + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "ATTACK2", + "name": "ATTACK2", + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 22, + "symbol": "ATTACK3", + "name": "ATTACK3", + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 23, + "symbol": "ATTACK4", + "name": "ATTACK4", + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 24, + "symbol": "ATTACK5", + "name": "ATTACK5", + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 25, + "symbol": "RELEASE1", + "name": "RELEASE1", + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 26, + "symbol": "RELEASE2", + "name": "RELEASE2", + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 27, + "symbol": "RELEASE3", + "name": "RELEASE3", + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 28, + "symbol": "RELEASE4", + "name": "RELEASE4", + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 29, + "symbol": "RELEASE5", + "name": "RELEASE5", + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 30, + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 31, + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 32, + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 33, + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 34, + "symbol": "V1", + "name": "V1", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 35, + "symbol": "V2", + "name": "V2", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 36, + "symbol": "V3", + "name": "V3", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 37, + "symbol": "V4", + "name": "V4", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 38, + "symbol": "V5", + "name": "V5", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 39, + "symbol": "V6", + "name": "V6", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 40, + "symbol": "V7", + "name": "V7", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 41, + "symbol": "V8", + "name": "V8", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 42, + "symbol": "V9", + "name": "V9", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 43, + "symbol": "V10", + "name": "V10", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 44, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 45, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbdelay_#_mbdelay_", + "name": "GxMultiBandDelay", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "DELAY1", + "name": "DELAY1", + "min_value": 24, + "max_value": 360, + "default_value": 30, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "DELAY2", + "name": "DELAY2", + "min_value": 24, + "max_value": 360, + "default_value": 60, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DELAY3", + "name": "DELAY3", + "min_value": 24, + "max_value": 360, + "default_value": 90, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "DELAY4", + "name": "DELAY4", + "min_value": 24, + "max_value": 360, + "default_value": 120, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "DELAY5", + "name": "DELAY5", + "min_value": 24, + "max_value": 360, + "default_value": 150, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "FEEDBACK1", + "name": "FEEDBACK1", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "FEEDBACK2", + "name": "FEEDBACK2", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "FEEDBACK3", + "name": "FEEDBACK3", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "FEEDBACK4", + "name": "FEEDBACK4", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "FEEDBACK5", + "name": "FEEDBACK5", + "min_value": 1, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "GAIN1", + "name": "GAIN1", + "min_value": -40, + "max_value": 2, + "default_value": -10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "GAIN2", + "name": "GAIN2", + "min_value": -40, + "max_value": 2, + "default_value": -5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "GAIN3", + "name": "GAIN3", + "min_value": -40, + "max_value": 2, + "default_value": -2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "GAIN4", + "name": "GAIN4", + "min_value": -40, + "max_value": 2, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "GAIN5", + "name": "GAIN5", + "min_value": -40, + "max_value": 2, + "default_value": -10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "V1", + "name": "V1", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "V2", + "name": "V2", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "V3", + "name": "V3", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 22, + "symbol": "V4", + "name": "V4", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 23, + "symbol": "V5", + "name": "V5", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 24, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 25, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbdistortion_#_mbdistortion_", + "name": "GxMultiBandDistortion", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "DRIVE1", + "name": "DRIVE1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "DRIVE2", + "name": "DRIVE2", + "min_value": 0, + "max_value": 1, + "default_value": 0.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DRIVE3", + "name": "DRIVE3", + "min_value": 0, + "max_value": 1, + "default_value": 0.649999976, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "DRIVE4", + "name": "DRIVE4", + "min_value": 0, + "max_value": 1, + "default_value": 0.25, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "DRIVE5", + "name": "DRIVE5", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "GAIN", + "name": "GAIN", + "min_value": -40, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "OFFSET1", + "name": "OFFSET1", + "min_value": 0, + "max_value": 0.5, + "default_value": 0.170000002, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "OFFSET2", + "name": "OFFSET2", + "min_value": 0, + "max_value": 0.5, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "OFFSET3", + "name": "OFFSET3", + "min_value": 0, + "max_value": 0.5, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "OFFSET4", + "name": "OFFSET4", + "min_value": 0, + "max_value": 0.5, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "OFFSET5", + "name": "OFFSET5", + "min_value": 0, + "max_value": 0.5, + "default_value": 0.170000002, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "V1", + "name": "V1", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "V2", + "name": "V2", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "V3", + "name": "V3", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "V4", + "name": "V4", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "V5", + "name": "V5", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbecho_#_mbecho_", + "name": "GxMultiBandEcho", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "PERCENT1", + "name": "PERCENT1", + "min_value": 0, + "max_value": 100, + "default_value": 10, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "PERCENT2", + "name": "PERCENT2", + "min_value": 0, + "max_value": 100, + "default_value": 30, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "PERCENT3", + "name": "PERCENT3", + "min_value": 0, + "max_value": 100, + "default_value": 45, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "PERCENT4", + "name": "PERCENT4", + "min_value": 0, + "max_value": 100, + "default_value": 20, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "PERCENT5", + "name": "PERCENT5", + "min_value": 0, + "max_value": 100, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "TIME1", + "name": "TIME1", + "min_value": 24, + "max_value": 360, + "default_value": 30, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "TIME2", + "name": "TIME2", + "min_value": 24, + "max_value": 360, + "default_value": 60, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "TIME3", + "name": "TIME3", + "min_value": 24, + "max_value": 360, + "default_value": 120, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "TIME4", + "name": "TIME4", + "min_value": 24, + "max_value": 360, + "default_value": 150, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "TIME5", + "name": "TIME5", + "min_value": 24, + "max_value": 360, + "default_value": 240, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "V1", + "name": "V1", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "V2", + "name": "V2", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "V3", + "name": "V3", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "V4", + "name": "V4", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "V5", + "name": "V5", + "min_value": -70, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbreverb_#_mbreverb_", + "name": "GxMultiBandReverb", + "plugin_class": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "ROOMSIZE1", + "name": "ROOMSIZE1", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "ROOMSIZE2", + "name": "ROOMSIZE2", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "ROOMSIZE3", + "name": "ROOMSIZE3", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "ROOMSIZE4", + "name": "ROOMSIZE4", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "ROOMSIZE5", + "name": "ROOMSIZE5", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "CROSSOVER_B1_B2", + "name": "CROSSOVER_B1_B2", + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "DAMP1", + "name": "DAMP1", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "DAMP2", + "name": "DAMP2", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "DAMP3", + "name": "DAMP3", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "DAMP4", + "name": "DAMP4", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "DAMP5", + "name": "DAMP5", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "V1", + "name": "V1", + "min_value": -70, + "max_value": 4, + "default_value": -70, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "V2", + "name": "V2", + "min_value": -70, + "max_value": 4, + "default_value": -70, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "V3", + "name": "V3", + "min_value": -70, + "max_value": 4, + "default_value": -70, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "V4", + "name": "V4", + "min_value": -70, + "max_value": 4, + "default_value": -70, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 20, + "symbol": "V5", + "name": "V5", + "min_value": -70, + "max_value": 4, + "default_value": -70, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "WET_DRY1", + "name": "WET_DRY1", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 22, + "symbol": "WET_DRY2", + "name": "WET_DRY2", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 23, + "symbol": "WET_DRY3", + "name": "WET_DRY3", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 24, + "symbol": "WET_DRY4", + "name": "WET_DRY4", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 25, + "symbol": "WET_DRY5", + "name": "WET_DRY5", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mole_#_mole_", + "name": "GxMole", + "plugin_class": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "BOOST", + "name": "BOOST", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "WET_DRY", + "name": "WET_DRY", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_muff_#_muff_", + "name": "GxMuff", + "plugin_class": "http://lv2plug.in/ns/lv2core#EQPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mxrdist_#_mxrdist_", + "name": "GxMXR Distortion", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_oc_2_#_oc_2_", + "name": "Gxoc_2", + "plugin_class": "http://lv2plug.in/ns/lv2core#PitchPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DIRECT", + "name": "DIRECT", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "OCTAVE1", + "name": "OCTAVE1", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "OCTAVE2", + "name": "OCTAVE2", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_phaser#_phaser", + "name": "GxPhaser", + "plugin_class": "http://lv2plug.in/ns/lv2core#PhaserPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"A phaser is an electronic sound processor used to filter a signal by creating a series of peaks and troughs in the frequency spectrum. The position of the peaks and troughs is typically modulated so that they vary over time, creating a sweeping effect. For this purpose, phasers usually include a low-frequency oscillator.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Phaser_%28effect%29\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "dry_wet", + "name": "Dry/Wet", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "level", + "name": "LEVEL", + "min_value": -60, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "speed", + "name": "SPEED", + "min_value": 0, + "max_value": 10, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_rangem_#_rangem_", + "name": "GxRangeMaster", + "plugin_class": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "BOOST", + "name": "BOOST", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "WET_DRY", + "name": "WET_DRY", + "min_value": 0, + "max_value": 100, + "default_value": 100, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_redeye#bigchump", + "name": "GxRedeye Big Chump", + "plugin_class": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "", + "ports": [ + { + "port_index": 0, + "symbol": "Gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "Tone", + "name": "Tone", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "Volume", + "name": "Volume", + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "Feedback", + "name": "Feedback", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "Vibe", + "name": "Vibe", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "Intensity", + "name": "Intensity", + "min_value": 0, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "Sinewave", + "name": "Sinewave", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_redeye#chump", + "name": "GxRedeye Chump", + "plugin_class": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "Gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "Tone", + "name": "Tone", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "Volume", + "name": "Volume", + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "Feedback", + "name": "Feedback", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "Vibe", + "name": "Vibe", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "Intensity", + "name": "Intensity", + "min_value": 0, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "Sinewave", + "name": "Sinewave", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_redeye#vibrochump", + "name": "GxRedeye Vibro Chump", + "plugin_class": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/worker#schedule" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/worker#schedule", + "http://lv2plug.in/ns/ext/urid#map", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "", + "ports": [ + { + "port_index": 0, + "symbol": "Gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "Tone", + "name": "Tone", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "Volume", + "name": "Volume", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "Feedback", + "name": "Feedback", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "Vibe", + "name": "Vibe", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "Speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "Intensity", + "name": "Intensity", + "min_value": 0, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "Sinewave", + "name": "Sinewave", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_reverb_stereo#_reverb_stereo", + "name": "GxReverb-Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n\"A Reverb simulates the component of sound that results from reflections from surrounding walls or objects. It is in effect a room simulator. Some people think it's just a delay effect with some filters, but it's way more complex than that.\"\n\n*Unofficial documentation\n\nsource: http://audacity.sourceforge.net/manual-1.2/effects_reverb.html\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "dry_wet", + "name": "Dry/Wet", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "lfo", + "name": "LFO", + "min_value": 0.200000003, + "max_value": 5, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "roomsize", + "name": "Roomsize", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "damp", + "name": "Damp", + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "mode", + "name": "Mode", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 0, + "label": "linear" + }, + { + "value": 1, + "label": "pingpong" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_room_simulator_#_room_simulator_", + "name": "Gxroom_simulator", + "plugin_class": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "EFFECT", + "name": "EFFECT", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "PREDELAYMS", + "name": "PREDELAYMS", + "min_value": 1, + "max_value": 200, + "default_value": 20, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "RT", + "name": "RT", + "min_value": 0, + "max_value": 1, + "default_value": 0.300000012, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "ROOMSIZE", + "name": "ROOMSIZE", + "min_value": 0, + "max_value": 3, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "DRYWET", + "name": "DRYWET", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_scream_#_scream_", + "name": "GxScreamingBird", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "SCREAM", + "name": "SCREAM", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_shimmizita_#_shimmizita_", + "name": "Gxshimmizita", + "plugin_class": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "CONTROL", + "name": "CONTROL", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "DEPTH", + "name": "DEPTH", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "DRYWET", + "name": "DRYWET", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "ENVELOPE", + "name": "ENVELOPE", + "min_value": 0.100000001, + "max_value": 3, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "F1", + "name": "F1", + "min_value": 50, + "max_value": 1000, + "default_value": 200, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "F2", + "name": "F2", + "min_value": 1500, + "max_value": 23520, + "default_value": 6000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "MODE", + "name": "MODE", + "min_value": -3, + "max_value": 3, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "PSDRYWET", + "name": "PSDRYWET", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "SHIFT", + "name": "SHIFT", + "min_value": -6, + "max_value": 6, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "SPEED", + "name": "SPEED", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "T60DS", + "name": "T60DS", + "min_value": 1, + "max_value": 8, + "default_value": 3, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "T60M", + "name": "T60M", + "min_value": 1, + "max_value": 8, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_studiopre#studiopre", + "name": "Gx Studio Preamp Mono", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nBased on simple Alembic F-2B vstudio preamp\n2 sections of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "bright", + "name": "Bright", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "volume", + "name": "Volume", + "min_value": 0, + "max_value": 20, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "bass", + "name": "Bass", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "middle", + "name": "Middle", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "treble", + "name": "Treble", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_studiopre_st#studiopre_st", + "name": "Gx Studio Preamp Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nBased on simple Alembic F-2B vstudio preamp\n2 sectionos of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "bright_l", + "name": "Bright_L", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "volume_l", + "name": "Volume_L", + "min_value": 0, + "max_value": 20, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "bass_l", + "name": "Bass_L", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "middle_l", + "name": "Middle_L", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "treble_l", + "name": "Treble_L", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "bright_r", + "name": "Bright_R", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "volume_r", + "name": "Volume_R", + "min_value": 0, + "max_value": 20, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "bass_r", + "name": "Bass_R", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "middle_r", + "name": "Middle_R", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "treble_r", + "name": "Treble_R", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_susta_#_susta_", + "name": "GxSustainer", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "SUSTAIN", + "name": "SUSTAIN", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "VOLUME", + "name": "VOLUME", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_switched_tremolo_#_switched_tremolo_", + "name": "Gxswitched_tremolo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "DEPTH", + "name": "DEPTH", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "FREQ0", + "name": "FREQ0", + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "FREQ1", + "name": "FREQ1", + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "FREQ2", + "name": "FREQ2", + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "FREQ3", + "name": "FREQ3", + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "STEPS", + "name": "STEPS", + "min_value": 1, + "max_value": 4, + "default_value": 4, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "SWITCHFREQ", + "name": "SWITCHFREQ", + "min_value": 0.25, + "max_value": 5, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_tremolo#_tremolo", + "name": "GxTremolo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nModel of a vactrol tremolo unit by \"transmogrify\"\n** c.f. http://sourceforge.net/apps/phpbb/guitarix/viewtopic.php?f=7&t=44&p=233&hilit=transmogrifox#p233\n** http://transmogrifox.webs.com/vactrol.m\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "dry_wet", + "name": "Dry/Wet", + "min_value": 0, + "max_value": 100, + "default_value": 50, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "mode", + "name": "Mode", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 1, + "label": "sine" + }, + { + "value": 0, + "label": "triangle" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "depth", + "name": "Depth", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "freq", + "name": "Freq", + "min_value": 0.100000001, + "max_value": 50, + "default_value": 5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_vibe_#_vibe_", + "name": "Gxvibe", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "WIDTH", + "name": "WIDTH", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "DEPTH", + "name": "DEPTH", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "WETDRY", + "name": "WETDRY", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "FB", + "name": "FB", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "TEMPO", + "name": "TEMPO", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 4.4000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "DF", + "name": "DF", + "min_value": -0.5, + "max_value": 0.5, + "default_value": 0.109999999, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "PAN", + "name": "PAN", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "CROSS", + "name": "CROSS", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_vibe_#_vibe_mono", + "name": "GxvibeMono", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "WIDTH", + "name": "WIDTH", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "DEPTH", + "name": "DEPTH", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "WETDRY", + "name": "WETDRY", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "FB", + "name": "FB", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "TEMPO", + "name": "TEMPO", + "min_value": 0.100000001, + "max_value": 10, + "default_value": 4.4000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_w20#w20", + "name": "Gx w20", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nBased on simple w20 F-2B vstudio preamp\n2 sectionos of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "level", + "name": "Level", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_zita_rev1_stereo#_zita_rev1_stereo", + "name": "GxZita_rev1-Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "level", + "name": "LEVEL", + "min_value": -70, + "max_value": 40, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "EQ2_FREQ", + "name": "EQ2_FREQ", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "EQ1_LEVEL", + "name": "EQ1_LEVEL", + "min_value": -15, + "max_value": 15, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "EQ1_FREQ", + "name": "EQ1_FREQ", + "min_value": 40, + "max_value": 2500, + "default_value": 315, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "IN_DELAY", + "name": "IN_DELAY", + "min_value": 20, + "max_value": 100, + "default_value": 60, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "LOW_RT60", + "name": "LOW_RT60", + "min_value": 1, + "max_value": 8, + "default_value": 3, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "LF_X", + "name": "LF_X", + "min_value": 50, + "max_value": 1000, + "default_value": 200, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "HF_DAMPING", + "name": "HF_DAMPING", + "min_value": 1500, + "max_value": 23520, + "default_value": 6000, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "MID_RT60", + "name": "MID_RT60", + "min_value": 1, + "max_value": 8, + "default_value": 2, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "DRY_WET_MIX", + "name": "DRY_WET_MIX", + "min_value": -1, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "EQ2_LEVEL", + "name": "EQ2_LEVEL", + "min_value": -15, + "max_value": 15, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "out1", + "name": "Out1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "in1", + "name": "In1", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxautowah#autowah", + "name": "GxAutoWah", + "plugin_class": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nAnalog wah emulation of the classic Dunlop Crybaby (*), in a auto-wah version.\n\n(*) 'Other product names modeled in this software are trademarks of their respective companies that do not endorse and are not associated or affiliated with MOD.\nDunlop Crybaby is trademark or trade name of other manufacturer and was used merely to identify the product whose sound was reviewed in the creation of this product.\nAll other trademarks are the property of their respective holders.'\n\n*Unofficial documentation\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxautowah#wah", + "name": "GxWah", + "plugin_class": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nAnalog wah emulation of the classic Dunlop Crybaby (*).\n\n(*) 'Other product names modeled in this software are trademarks of their respective companies that do not endorse and are not associated or affiliated with MOD.\nDunlop Crybaby is trademark or trade name of other manufacturer and was used merely to identify the product whose sound was reviewed in the creation of this product.\nAll other trademarks are the property of their respective holders.'\n\n*Unofficial documentation\n", + "ports": [ + { + "port_index": 0, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "fslider1_", + "name": "Wah", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxbooster#booster", + "name": "GxBooster", + "plugin_class": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nA 2 band boost plugin. With this plugin you can boost the high and the low frequencies independently.\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "fslider0_", + "name": "H Level", + "min_value": 0.5, + "max_value": 20, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "fslider1_", + "name": "B Level", + "min_value": 0.5, + "max_value": 20, + "default_value": 1, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxechocat#echocat", + "name": "GxEchoCat", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nA tape delay simulation plugin.\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "swell", + "name": "Swell", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "sustain", + "name": "Sustain", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "bpm", + "name": "BPM", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "head1", + "name": "Head 1", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "head2", + "name": "Head 2", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "head3", + "name": "Head 3", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxmetal_amp#metal_amp", + "name": "GxMetalAmp", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": 1, + "max_value": 20, + "default_value": 10.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "PREGAIN", + "name": "PREGAIN", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "GAIN1", + "name": "GAIN1", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxmetal_head#metal_head", + "name": "GxMetalHead", + "plugin_class": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/buf-size#boundedBlockLength" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "TONE", + "name": "TONE", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "DRIVE", + "name": "DRIVE", + "min_value": 0, + "max_value": 1, + "default_value": 0.319999993, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "PREGAIN", + "name": "PREGAIN", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "GAIN1", + "name": "GAIN1", + "min_value": -20, + "max_value": 20, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtape#tape", + "name": "GxTape", + "plugin_class": "http://lv2plug.in/ns/lv2core#Plugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "", + "ports": [ + { + "port_index": 0, + "symbol": "on", + "name": "On", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "wowdepth", + "name": "WowDepth", + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "wowfreq", + "name": "WowFreq", + "min_value": 0, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "flutdepth", + "name": "FlutterDepth", + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "flutfreq", + "name": "FluterFreq", + "min_value": 4, + "max_value": 60, + "default_value": 4, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "hiss", + "name": "Hiss", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "type", + "name": "Type", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "speed", + "name": "Speed", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "gain", + "name": "Gain", + "min_value": -20, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "meterlevel", + "name": "MeterLevel", + "min_value": -90, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtape_st#tape", + "name": "Gx Tape Stereo", + "plugin_class": "http://lv2plug.in/ns/lv2core#Plugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "", + "ports": [ + { + "port_index": 0, + "symbol": "on", + "name": "On", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "wowdepth", + "name": "WowDepth", + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "wowfreq", + "name": "WowFreq", + "min_value": 0, + "max_value": 4, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "flutdepth", + "name": "FlutterDepth", + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "flutfreq", + "name": "FluterFreq", + "min_value": 4, + "max_value": 60, + "default_value": 4, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "hiss", + "name": "Hiss", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "type", + "name": "Type", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "speed", + "name": "Speed", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "outl", + "name": "OutL", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "outr", + "name": "OutR", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "inl", + "name": "InL", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "inr", + "name": "InR", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "meterlevel", + "name": "MeterLevel", + "min_value": -90, + "max_value": 10, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtilttone#tilttone", + "name": "GxTiltTone", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\nSimple Tilt tone control\n\nThe tilt control imposes a shelving function, which attenuates half of frequency band and augments the other half. In other words, it is special type of a tone control that, unlike the typical tone control that boosts or cuts just the highs or mids or lows, shifts both highs and lows at once. \n\n*Unofficial documentation\n\nsource: http://www.tubecad.com/2013/06/blog0266.htm\n", + "ports": [ + { + "port_index": 0, + "symbol": "body", + "name": "Bpdy", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "tone", + "name": "Tone", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "level", + "name": "Level", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxts9#ts9sim", + "name": "GxTubeScreamer", + "plugin_class": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\nAnalog distortion emulation of the classic Ibanez TS-9 (*)\n\n(*) 'Other product names modeled in this software are trademarks of their respective companies that do not endorse and are not associated or affiliated with MOD.\nIbanez TS-9 is trademark or trade name of other manufacturer and was used merely to identify the product whose sound was reviewed in the creation of this product.\nAll other trademarks are the property of their respective holders.'\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "fslider0_", + "name": "Level", + "min_value": -20, + "max_value": 4, + "default_value": -16, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "fslider1_", + "name": "Tone", + "min_value": 100, + "max_value": 1000, + "default_value": 400, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "fslider2_", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubedelay#tubedelay", + "name": "GxTubeDelay", + "plugin_class": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "delay", + "name": "Delay", + "min_value": 1, + "max_value": 2500, + "default_value": 160, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "feedback", + "name": "Feedback", + "min_value": 0.00999999978, + "max_value": 1, + "default_value": 0.00999999978, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "level", + "name": "Level", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "in", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubetremelo#tubetremelo", + "name": "GxTubeTremelo", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nModel of a vactrol tremolo unit by \"transmogrify\"\nc.f. http://sourceforge.net/apps/phpbb/guitarix/viewtopic.php?f=7&t=44&p=233&hilit=transmogrifox#p233\nhttp://transmogrifox.webs.com/vactrol.m\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "sinewave", + "name": "SineWave", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "depth", + "name": "Depth", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 14, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubevibrato#tubevibrato", + "name": "GxTubeVibrato", + "plugin_class": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\nAttempt at a true vibrato\nAnd it works well!\nSounds very sweet with tubes wrapped\n\n*Unofficial documentation\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "sinewave", + "name": "SineWave", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "depth", + "name": "Depth", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "speed", + "name": "Speed", + "min_value": 0.100000001, + "max_value": 14, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "drive", + "name": "Drive", + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "gain", + "name": "Gain", + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtuner#tuner", + "name": "GxTuner", + "plugin_class": "http://lv2plug.in/ns/lv2core#AnalyserPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "required_features": [], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Guitarix team", + "author_homepage": "", + "comment": "\n\n...\n\n", + "ports": [ + { + "port_index": 0, + "symbol": "FREQ", + "name": "FREQ", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "REFFREQ", + "name": "REFFREQ", + "min_value": 427, + "max_value": 453, + "default_value": 440, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 2, + "symbol": "TUNER_MODE", + "name": "Tuner Mode", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 12, + "label": "Drop A#" + }, + { + "value": 8, + "label": "Double Drop D" + }, + { + "value": 11, + "label": "Drop B" + }, + { + "value": 10, + "label": "Drop C#" + }, + { + "value": 9, + "label": "Drop C" + }, + { + "value": 6, + "label": "Full Step Down" + }, + { + "value": 7, + "label": "1 and 1/2 Steps Down" + }, + { + "value": 15, + "label": "Open D Minor" + }, + { + "value": 16, + "label": "Open G" + }, + { + "value": 13, + "label": "Drop A" + }, + { + "value": 14, + "label": "Open D" + }, + { + "value": 17, + "label": "Open G Minor" + }, + { + "value": 18, + "label": "Open C" + }, + { + "value": 19, + "label": "Open C#" + }, + { + "value": 20, + "label": "Open C Minor" + }, + { + "value": 21, + "label": "Open E7" + }, + { + "value": 22, + "label": "Open E Minor7" + }, + { + "value": 23, + "label": "Open G Major7" + }, + { + "value": 24, + "label": "Open A Minor" + }, + { + "value": 25, + "label": "Open A Minor7" + }, + { + "value": 26, + "label": "Open A" + }, + { + "value": 27, + "label": "C Tuning" + }, + { + "value": 28, + "label": "C# Tuning" + }, + { + "value": 29, + "label": "Bb Tuning" + }, + { + "value": 30, + "label": "A to A (Baritone)" + }, + { + "value": 31, + "label": "Open Dsus2" + }, + { + "value": 32, + "label": "Open Gsus2" + }, + { + "value": 33, + "label": "G6" + }, + { + "value": 34, + "label": "Overtone" + }, + { + "value": 35, + "label": "Pentatonic" + }, + { + "value": 0, + "label": "(Chromatic)" + }, + { + "value": 36, + "label": "Minor Third" + }, + { + "value": 37, + "label": "Major Third" + }, + { + "value": 38, + "label": "All Fourths" + }, + { + "value": 39, + "label": "Augmented Fourths" + }, + { + "value": 40, + "label": "Slow Motion" + }, + { + "value": 41, + "label": "Admiral" + }, + { + "value": 42, + "label": "Buzzard" + }, + { + "value": 43, + "label": "Face" + }, + { + "value": 44, + "label": "Four and Twenty" + }, + { + "value": 45, + "label": "Ostrich" + }, + { + "value": 1, + "label": "Standard/E" + }, + { + "value": 46, + "label": "Capo 200" + }, + { + "value": 47, + "label": "Balalaika" + }, + { + "value": 48, + "label": "Cittern One" + }, + { + "value": 49, + "label": "Cittern Two" + }, + { + "value": 50, + "label": "Dobro" + }, + { + "value": 51, + "label": "Lefty" + }, + { + "value": 52, + "label": "Mandoguitar" + }, + { + "value": 53, + "label": "Rusty Cage" + }, + { + "value": 54, + "label": "Hardcore" + }, + { + "value": 2, + "label": "Standard/Es" + }, + { + "value": 3, + "label": "Open E" + }, + { + "value": 4, + "label": "Drop D" + }, + { + "value": 5, + "label": "Half Step Down" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 3, + "symbol": "TEMPERAMENT", + "name": "TEMPERAMENT", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 4, + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 5, + "symbol": "MAXL", + "name": "MAXL", + "min_value": 0, + "max_value": 1000, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + }, + { + "port_index": 6, + "symbol": "RESET", + "name": "RESET", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 7, + "symbol": "LEVEL", + "name": "LEVEL", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 8, + "symbol": "CHANNEL", + "name": "CHANNELL", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [ + { + "value": 6, + "label": "6" + }, + { + "value": 4, + "label": "4" + }, + { + "value": 5, + "label": "5" + }, + { + "value": 1, + "label": "1" + }, + { + "value": 3, + "label": "3" + }, + { + "value": 2, + "label": "2" + }, + { + "value": 0, + "label": "0" + }, + { + "value": 7, + "label": "7" + }, + { + "value": 16, + "label": "16" + }, + { + "value": 14, + "label": "14" + }, + { + "value": 15, + "label": "15" + }, + { + "value": 13, + "label": "13" + }, + { + "value": 8, + "label": "8" + }, + { + "value": 12, + "label": "12" + }, + { + "value": 9, + "label": "9" + }, + { + "value": 11, + "label": "11" + }, + { + "value": 10, + "label": "10" + } + ], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 9, + "symbol": "MIDI_ON", + "name": "MIDI_ON", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 10, + "symbol": "FASTNOTE", + "name": "FASTNOTE", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 11, + "symbol": "PITCHBEND", + "name": "PITCHBEND", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 12, + "symbol": "SINGLENOTE", + "name": "SINGLENOTE", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 13, + "symbol": "BPM", + "name": "BPM", + "min_value": 0, + "max_value": 360, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 14, + "symbol": "VELOCITY", + "name": "VELOCITY", + "min_value": 0, + "max_value": 127, + "default_value": 64, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 15, + "symbol": "VERIFY", + "name": "VERIFY", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 16, + "symbol": "GATE", + "name": "GATE", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 17, + "symbol": "SYNTHFREQ", + "name": "SYNTHFREQ", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 18, + "symbol": "GAIN", + "name": "GAIN", + "min_value": 0, + "max_value": 0, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": true, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 19, + "symbol": "midi_out", + "name": "MIDI Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": true + }, + { + "port_index": 20, + "symbol": "out", + "name": "Out", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 21, + "symbol": "in", + "name": "In", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": true, + "is_control_port": false, + "is_audio_port": true, + "is_atom_port": true, + "is_valid": true, + "supports_midi": false + } + ] + }, + { + "uri": "http://lv2plug.in/plugins/eg-echo", + "name": "Object Serialization Tester", + "plugin_class": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "supported_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable", + "http://lv2plug.in/ns/ext/urid#map" + ], + "required_features": [ + "http://lv2plug.in/ns/ext/urid#map" + ], + "optional_features": [ + "http://lv2plug.in/ns/lv2core#hardRTCapable" + ], + "author_name": "Robin Davies", + "author_homepage": "http://two-play.com/", + "comment": "Plugin used to test text conversion of patch property objects.", + "ports": [ + { + "port_index": 0, + "symbol": "control", + "name": "Control", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": true, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": true, + "supports_midi": false + }, + { + "port_index": 1, + "symbol": "notify", + "name": "Notify", + "min_value": 0, + "max_value": 1, + "default_value": 0, + "scale_points": [], + "is_input": false, + "is_output": false, + "is_control_port": false, + "is_audio_port": false, + "is_atom_port": false, + "is_valid": false, + "supports_midi": false + } + ] + } +] \ No newline at end of file diff --git a/react/public/serve.json b/react/public/serve.json new file mode 100644 index 0000000..6ef9c78 --- /dev/null +++ b/react/public/serve.json @@ -0,0 +1,4 @@ +{ + "directoryListing": false + +} \ No newline at end of file diff --git a/react/public/var/config.json b/react/public/var/config.json new file mode 100644 index 0000000..c1902a0 --- /dev/null +++ b/react/public/var/config.json @@ -0,0 +1,11 @@ +{ + "socket_server_port": 80, + "socket_server_address": "*", + + "max_upload_size": 1048576, + + "ui_plugins": [ + + ] + +} \ No newline at end of file diff --git a/react/public/var/current_pedalboard.json b/react/public/var/current_pedalboard.json new file mode 100644 index 0000000..37ff57f --- /dev/null +++ b/react/public/var/current_pedalboard.json @@ -0,0 +1,76 @@ +{ + "name": "Untitled", + "items": [ + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + + }, + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "controlValues": [] + }, + { + "uri": "uri://two-play/piddle/pedalboard#Split", + "isEnabled": true, + "controlValues": [ + { "key": "splitType", "value": 0}, + { "key": "select", "value": 1}, + { "key": "mix", "value": 0.3} + ], + + "topChain": [ + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + }, + { + + "uri": "uri://two-play/piddle/pedalboard#Split", + "isEnabled": true, + "controlValues": [ + { "key": "splitType", "value": 0}, + { "key": "select", "value": 1}, + { "key": "mix", "value": 0.3} + ], + "topChain": [ + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + } + ], + "bottomChain": [ + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + } + ] + } + + ], + "bottomChain": [ + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + } + ] + }, + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + }, + { + "uri": "uri://two-play/piddle/pedalboard#Empty", + "isEnabled": true, + "controlValues": [] + } + + + ] +} diff --git a/react/public/var/plugin_classes.json b/react/public/var/plugin_classes.json new file mode 100644 index 0000000..a8c42f5 --- /dev/null +++ b/react/public/var/plugin_classes.json @@ -0,0 +1,276 @@ +{ + "uri": "http://lv2plug.in/ns/lv2core#Plugin", + "display_name": "Plugin", + "parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase", + "plugin_type": "Plugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "display_name": "Delay", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DelayPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ReverbPlugin", + "display_name": "Reverb", + "parent_uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", + "plugin_type": "ReverbPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "display_name": "Distortion", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DistortionPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#WaveshaperPlugin", + "display_name": "Waveshaper", + "parent_uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin", + "plugin_type": "WaveshaperPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "display_name": "Dynamics", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "DynamicsPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin", + "display_name": "Amplifier", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "AmplifierPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin", + "display_name": "Compressor", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "CompressorPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#EnvelopePlugin", + "display_name": "Envelope", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "EnvelopePlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ExpanderPlugin", + "display_name": "Expander", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "ExpanderPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#GatePlugin", + "display_name": "Gate", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "GatePlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#LimiterPlugin", + "display_name": "Limiter", + "parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin", + "plugin_type": "LimiterPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "display_name": "Filter", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "FilterPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AllpassPlugin", + "display_name": "Allpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "AllpassPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#BandpassPlugin", + "display_name": "Bandpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "BandpassPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#CombPlugin", + "display_name": "Comb", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "CombPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "display_name": "Equaliser", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "EQPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#MultiEQPlugin", + "display_name": "Multiband", + "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "plugin_type": "MultiEQPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ParaEQPlugin", + "display_name": "Parametric", + "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin", + "plugin_type": "ParaEQPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#HighpassPlugin", + "display_name": "Highpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "HighpassPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#LowpassPlugin", + "display_name": "Lowpass", + "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin", + "plugin_type": "LowpassPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "display_name": "Generator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "GeneratorPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ConstantPlugin", + "display_name": "Constant", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "ConstantPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#InstrumentPlugin", + "display_name": "Instrument", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "InstrumentPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#OscillatorPlugin", + "display_name": "Oscillator", + "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin", + "plugin_type": "OscillatorPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "display_name": "Modulator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "ModulatorPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#ChorusPlugin", + "display_name": "Chorus", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "ChorusPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FlangerPlugin", + "display_name": "Flanger", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "FlangerPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#PhaserPlugin", + "display_name": "Phaser", + "parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin", + "plugin_type": "PhaserPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", + "display_name": "Simulator", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SimulatorPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin", + "display_name": "Spatial", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SpatialPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", + "display_name": "Spectral", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "SpectralPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#PitchPlugin", + "display_name": "Pitch Shifter", + "parent_uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", + "plugin_type": "PitchPlugin", + "children": [] + } + ] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "display_name": "Utility", + "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", + "plugin_type": "UtilityPlugin", + "children": [ + { + "uri": "http://lv2plug.in/ns/lv2core#AnalyserPlugin", + "display_name": "Analyser", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "AnalyserPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#ConverterPlugin", + "display_name": "Converter", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "ConverterPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#FunctionPlugin", + "display_name": "Function", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "FunctionPlugin", + "children": [] + }, + { + "uri": "http://lv2plug.in/ns/lv2core#MixerPlugin", + "display_name": "Mixer", + "parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", + "plugin_type": "MixerPlugin", + "children": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/react/public/var/uiplugins.json b/react/public/var/uiplugins.json new file mode 100644 index 0000000..995335b --- /dev/null +++ b/react/public/var/uiplugins.json @@ -0,0 +1,9662 @@ +[ + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_aclipper_#_aclipper_", + "name": "GxRat", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 3, + "min_value": -20, + "max_value": 12, + "default_value": -2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TONE", + "name": "TONE", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_alembic#alembic", + "name": "Gx Alembic", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nBased on simple Alembic F-2B vstudio preamp\n2 sectionos of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "input", + "name": "Input", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "bass", + "name": "Bass", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "middle", + "name": "Middle", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "treble", + "name": "Treble", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "volume", + "name": "Volume", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_amp#GUITARIX", + "name": "GxAmplifier-X", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\nThis plugin is the combination of guitarix's head, tonestack and cabinet, which, in that order, composes the signal path. In the tube-amp part, \"PreGain\" corresponds to the gain used at the amp input, \"Drive\" controls the power amp gain, \"Distortion\" is a blend between clean and distorted sound (lower boundary is all clean, upper boundary all distorted) and \"MasterGain\" controls the output gain. Mainly, the responsible for the signal distortion are \"PreGain\" and \"Drive\" parameters. Besides that, there is a list of possible valve combinations so you can vary your distortion.\n\nAt the Tonestack part, we find a basic equalization set (\"Bass\", \"Middle\", \"Treble\" and \"Presence\") and a list of tone-responses from a few well-known amps, you can check this list in the link at the end of this description (there might be some version differences).\n\nFinally, at the Cabinet path, we have \"Cabinet\", which corresponds to another output gain, it doesn't distort the signal so it can be used as a Master output and there's another list, containing a virtual sound of the cabinet of speakers selected (more details in the link below).\n\nBased on: \nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=EnhancedUI\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Tonestack\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Cabinet_Impulse_Response_convolution\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "MasterGain", + "name": "MasterGain", + "index": 0, + "min_value": -20, + "max_value": 20, + "default_value": -15, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PreGain", + "name": "PreGain", + "index": 1, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Distortion", + "name": "Distortion", + "index": 2, + "min_value": 1, + "max_value": 100, + "default_value": 20, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Drive", + "name": "Drive", + "index": 3, + "min_value": 0.00999999978, + "max_value": 1, + "default_value": 0.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Middle", + "name": "Middle", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Bass", + "name": "Bass", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Treble", + "name": "Treble", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Cabinet", + "name": "Cabinet", + "index": 7, + "min_value": 1, + "max_value": 20, + "default_value": 10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Presence", + "name": "Presence", + "index": 8, + "min_value": 1, + "max_value": 10, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "model", + "name": "Model", + "index": 9, + "min_value": 0, + "max_value": 17, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "12ax7" + }, + { + "value": 1, + "label": "12AU7" + }, + { + "value": 2, + "label": "12AT7" + }, + { + "value": 3, + "label": "6DJ8" + }, + { + "value": 4, + "label": "6C16" + }, + { + "value": 5, + "label": "6V6" + }, + { + "value": 6, + "label": "12ax7 feedback" + }, + { + "value": 7, + "label": "12AU7 feedback" + }, + { + "value": 8, + "label": "12AT7 feedback" + }, + { + "value": 9, + "label": "6DJ8 feedback" + }, + { + "value": 10, + "label": "pre 12ax7/ master 6V6" + }, + { + "value": 11, + "label": "pre 12AU7/ master 6V6" + }, + { + "value": 12, + "label": "pre 12AT7/ master 6V6" + }, + { + "value": 13, + "label": "pre 6DJ8/ master 6V6" + }, + { + "value": 14, + "label": "pre 12ax7/ push-pull 6V6" + }, + { + "value": 15, + "label": "pre 12AU7/ push-pull 6V6" + }, + { + "value": 16, + "label": "pre 12AT7/ push pull 6V6" + }, + { + "value": 17, + "label": "pre 6DJ8/ push-pull 6V6" + } + ] + }, + { + "symbol": "t_model", + "name": "Tonestack Model", + "index": 10, + "min_value": 0, + "max_value": 26, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "default" + }, + { + "value": 1, + "label": "Bassman Style" + }, + { + "value": 2, + "label": "Twin Reverb Style" + }, + { + "value": 3, + "label": "Princeton Style" + }, + { + "value": 4, + "label": "JCM-800 Style" + }, + { + "value": 5, + "label": "JCM-2000 Style" + }, + { + "value": 6, + "label": "M-Lead Style" + }, + { + "value": 7, + "label": "M2199 Style" + }, + { + "value": 8, + "label": "AC-30 Style" + }, + { + "value": 9, + "label": "Mesa Boogie Style" + }, + { + "value": 10, + "label": "SOL 100 Style" + }, + { + "value": 11, + "label": "JTM-45 Style" + }, + { + "value": 12, + "label": "AC-15 Style" + }, + { + "value": 13, + "label": "Peavey Style" + }, + { + "value": 14, + "label": "Ibanez Style" + }, + { + "value": 15, + "label": "Roland Style" + }, + { + "value": 16, + "label": "Ampeg Style" + }, + { + "value": 17, + "label": "Rev.Rocket Style" + }, + { + "value": 18, + "label": "MIG 100 H Style" + }, + { + "value": 19, + "label": "Triple Giant Style" + }, + { + "value": 20, + "label": "Trio Preamp Style" + }, + { + "value": 21, + "label": "Hughes&Kettner Style" + }, + { + "value": 22, + "label": "Fender Junior Style" + }, + { + "value": 23, + "label": "Fender Style" + }, + { + "value": 24, + "label": "Fender Deville Style" + }, + { + "value": 25, + "label": "Gibsen Style" + }, + { + "value": 26, + "label": "Off" + } + ] + }, + { + "symbol": "c_model", + "name": "Cab Model", + "index": 11, + "min_value": 0, + "max_value": 18, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "4x12" + }, + { + "value": 1, + "label": "2x12" + }, + { + "value": 2, + "label": "1x12" + }, + { + "value": 3, + "label": "4x10" + }, + { + "value": 4, + "label": "2x10" + }, + { + "value": 5, + "label": "HighGain Style" + }, + { + "value": 6, + "label": "Twin Style" + }, + { + "value": 7, + "label": "Bassman Style" + }, + { + "value": 8, + "label": "Marshall Style" + }, + { + "value": 9, + "label": "AC30 Style" + }, + { + "value": 10, + "label": "Princeton Style" + }, + { + "value": 11, + "label": "A2 Style" + }, + { + "value": 12, + "label": "1x15" + }, + { + "value": 13, + "label": "Mesa Style" + }, + { + "value": 14, + "label": "Briliant" + }, + { + "value": 15, + "label": "Vitalize" + }, + { + "value": 16, + "label": "Charisma" + }, + { + "value": 17, + "label": "1x8" + }, + { + "value": 18, + "label": "Off" + } + ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_amp_stereo#GUITARIX_ST", + "name": "GxAmplifier-Stereo-X", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\nStereo version of gx_amp.\n\nThis plugin is the combination of guitarix's head, tonestack and cabinet, which, in that order, composes the signal path. In the tube-amp part, \"PreGain\" corresponds to the gain used at the amp input, \"Drive\" controls the power amp gain, \"Distortion\" is a blend between clean and distorted sound (lower boundary is all clean, upper boundary all distorted) and \"MasterGain\" controls the output gain. Mainly, the responsible for the signal distortion are \"PreGain\" and \"Drive\" parameters. Besides that, there is a list of possible valve combinations so you can vary your distortion.\n\nAt the Tonestack part, we find a basic equalization set (\"Bass\", \"Middle\", \"Treble\" and \"Presence\") and a list of tone-responses from a few well-known amps, you can check this list in the link at the end of this description (there might be some version differences).\n\nFinally, at the Cabinet path, we have \"Cabinet\", which corresponds to another output gain, it doesn't distort the signal so it can be used as a Master output and there's another list, containing a virtual sound of the cabinet of speakers selected (more details in the link below).\n\nBased on: \nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=EnhancedUI\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Tonestack\nhttps://sourceforge.net/apps/mediawiki/guitarix/index.php?title=Cabinet_Impulse_Response_convolution\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "MasterGain", + "name": "MasterGain", + "index": 0, + "min_value": -20, + "max_value": 20, + "default_value": -15, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PreGain", + "name": "PreGain", + "index": 1, + "min_value": -20, + "max_value": 20, + "default_value": -15, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Distortion", + "name": "Distortion", + "index": 2, + "min_value": 1, + "max_value": 100, + "default_value": 20, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Drive", + "name": "Drive", + "index": 3, + "min_value": 0.00999999978, + "max_value": 1, + "default_value": 0.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Middle", + "name": "Middle", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Bass", + "name": "Bass", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Treble", + "name": "Treble", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Cabinet", + "name": "Cabinet", + "index": 7, + "min_value": 1, + "max_value": 20, + "default_value": 10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Presence", + "name": "Presence", + "index": 8, + "min_value": 1, + "max_value": 10, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "model", + "name": "Model", + "index": 9, + "min_value": 0, + "max_value": 17, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "12ax7" + }, + { + "value": 1, + "label": "12AU7" + }, + { + "value": 2, + "label": "12AT7" + }, + { + "value": 3, + "label": "6DJ8" + }, + { + "value": 4, + "label": "6C16" + }, + { + "value": 5, + "label": "6V6" + }, + { + "value": 6, + "label": "12ax7 feedback" + }, + { + "value": 7, + "label": "12AU7 feedback" + }, + { + "value": 8, + "label": "12AT7 feedback" + }, + { + "value": 9, + "label": "6DJ8 feedback" + }, + { + "value": 10, + "label": "pre 12ax7/ master 6V6" + }, + { + "value": 11, + "label": "pre 12AU7/ master 6V6" + }, + { + "value": 12, + "label": "pre 12AT7/ master 6V6" + }, + { + "value": 13, + "label": "pre 6DJ8/ master 6V6" + }, + { + "value": 14, + "label": "pre 12ax7/ push-pull 6V6" + }, + { + "value": 15, + "label": "pre 12AU7/ push-pull 6V6" + }, + { + "value": 16, + "label": "pre 12AT7/ push pull 6V6" + }, + { + "value": 17, + "label": "pre 6DJ8/ push-pull 6V6" + } + ] + }, + { + "symbol": "t_model", + "name": "Tonestack Model", + "index": 10, + "min_value": 0, + "max_value": 26, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "default" + }, + { + "value": 1, + "label": "Bassman Style" + }, + { + "value": 2, + "label": "Twin Reverb Style" + }, + { + "value": 3, + "label": "Princeton Style" + }, + { + "value": 4, + "label": "JCM-800 Style" + }, + { + "value": 5, + "label": "JCM-2000 Style" + }, + { + "value": 6, + "label": "M-Lead Style" + }, + { + "value": 7, + "label": "M2199 Style" + }, + { + "value": 8, + "label": "AC-30 Style" + }, + { + "value": 9, + "label": "Mesa Boogie Style" + }, + { + "value": 10, + "label": "SOL 100 Style" + }, + { + "value": 11, + "label": "JTM-45 Style" + }, + { + "value": 12, + "label": "AC-15 Style" + }, + { + "value": 13, + "label": "Peavey Style" + }, + { + "value": 14, + "label": "Ibanez Style" + }, + { + "value": 15, + "label": "Roland Style" + }, + { + "value": 16, + "label": "Ampeg Style" + }, + { + "value": 17, + "label": "Rev.Rocket Style" + }, + { + "value": 18, + "label": "MIG 100 H Style" + }, + { + "value": 19, + "label": "Triple Giant Style" + }, + { + "value": 20, + "label": "Trio Preamp Style" + }, + { + "value": 21, + "label": "Hughes&Kettner Style" + }, + { + "value": 22, + "label": "Fender Junior Style" + }, + { + "value": 23, + "label": "Fender Style" + }, + { + "value": 24, + "label": "Fender Deville Style" + }, + { + "value": 25, + "label": "Gibsen Style" + }, + { + "value": 26, + "label": "Off" + } + ] + }, + { + "symbol": "c_model", + "name": "Cab Model", + "index": 11, + "min_value": 0, + "max_value": 18, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "4x12" + }, + { + "value": 1, + "label": "2x12" + }, + { + "value": 2, + "label": "1x12" + }, + { + "value": 3, + "label": "4x10" + }, + { + "value": 4, + "label": "2x10" + }, + { + "value": 5, + "label": "HighGain Style" + }, + { + "value": 6, + "label": "Twin Style" + }, + { + "value": 7, + "label": "Bassman Style" + }, + { + "value": 8, + "label": "Marshall Style" + }, + { + "value": 9, + "label": "AC30 Style" + }, + { + "value": 10, + "label": "Princeton Style" + }, + { + "value": 11, + "label": "A2 Style" + }, + { + "value": 12, + "label": "1x15" + }, + { + "value": 13, + "label": "Mesa Style" + }, + { + "value": 14, + "label": "Briliant" + }, + { + "value": 15, + "label": "Vitalize" + }, + { + "value": 16, + "label": "Charisma" + }, + { + "value": 17, + "label": "1x8" + }, + { + "value": 18, + "label": "Off" + } + ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_barkgraphiceq_#_barkgraphiceq_", + "name": "GxBarkGraphicEQ", + "plugin_type": "EQPlugin", + "plugin_display_type": "Equaliser", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nA Graphic Equalizer with Bark frequency scale.\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "G1", + "name": "G1", + "index": 0, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G2", + "name": "G2", + "index": 1, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G3", + "name": "G3", + "index": 2, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G4", + "name": "G4", + "index": 3, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G5", + "name": "G5", + "index": 4, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G6", + "name": "G6", + "index": 5, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G7", + "name": "G7", + "index": 6, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G8", + "name": "G8", + "index": 7, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G9", + "name": "G9", + "index": 8, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G10", + "name": "G10", + "index": 9, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G11", + "name": "G11", + "index": 10, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G12", + "name": "G12", + "index": 11, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G13", + "name": "G13", + "index": 12, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G14", + "name": "G14", + "index": 13, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G15", + "name": "G15", + "index": 14, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G16", + "name": "G16", + "index": 15, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G17", + "name": "G17", + "index": 16, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G18", + "name": "G18", + "index": 17, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G19", + "name": "G19", + "index": 18, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G20", + "name": "G20", + "index": 19, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G21", + "name": "G21", + "index": 20, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G22", + "name": "G22", + "index": 21, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G23", + "name": "G23", + "index": 22, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G24", + "name": "G24", + "index": 23, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_bmp_#_bmp_", + "name": "GxBigMuffPi", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "SUSTAIN", + "name": "SUSTAIN", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TONE", + "name": "TONE", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_bossds1_#_bossds1_", + "name": "GxBoss DS1", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 2, + "min_value": -20, + "max_value": 12, + "default_value": -2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TONE", + "name": "TONE", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_cabinet#CABINET", + "name": "GxCabinet", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "CLevel", + "name": "Cabinet", + "index": 0, + "min_value": 0.5, + "max_value": 5, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CBass", + "name": "Bass", + "index": 1, + "min_value": -10, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CTreble", + "name": "Treble", + "index": 2, + "min_value": -10, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "c_model", + "name": "Cab Model", + "index": 3, + "min_value": 0, + "max_value": 18, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "4x12" + }, + { + "value": 1, + "label": "2x12" + }, + { + "value": 2, + "label": "1x12" + }, + { + "value": 3, + "label": "4x10" + }, + { + "value": 4, + "label": "2x10" + }, + { + "value": 5, + "label": "HighGain Style" + }, + { + "value": 6, + "label": "Twin Style" + }, + { + "value": 7, + "label": "Bassman Style" + }, + { + "value": 8, + "label": "Marshall Style" + }, + { + "value": 9, + "label": "AC30 Style" + }, + { + "value": 10, + "label": "Princeton Style" + }, + { + "value": 11, + "label": "A2 Style" + }, + { + "value": 12, + "label": "1x15" + }, + { + "value": 13, + "label": "Mesa Style" + }, + { + "value": 14, + "label": "Briliant" + }, + { + "value": 15, + "label": "Vitalize" + }, + { + "value": 16, + "label": "Charisma" + }, + { + "value": 17, + "label": "1x8" + }, + { + "value": 18, + "label": "Off" + } + ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_chorus_stereo#_chorus_stereo", + "name": "GxChorus-Stereo", + "plugin_type": "ChorusPlugin", + "plugin_display_type": "Chorus", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n\"In music, a chorus effect (sometimes chorusing or chorused effect) occurs when individual sounds with roughly the same timbre and nearly (but never exactly) the same pitch converge and are perceived as one. While similar sounds coming from multiple sources can occur naturally (as in the case of a choir or string orchestra), it can also be simulated using an electronic effects unit or signal processing device.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Chorus_effect\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "level", + "name": "Level", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "delay", + "name": "Delay", + "index": 1, + "min_value": 0, + "max_value": 0.200000003, + "default_value": 0.0199999996, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "depth", + "name": "Depth", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.0199999996, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "freq", + "name": "Freq", + "index": 3, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 3, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_colwah_#_colwah_", + "name": "GxWahwah", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "WAH", + "name": "WAH", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FREQ", + "name": "FREQ", + "index": 3, + "min_value": 24, + "max_value": 360, + "default_value": 24, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MODE", + "name": "MODE", + "index": 4, + "min_value": 0, + "max_value": 2, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "manual" + }, + { + "value": 1, + "label": "auto" + }, + { + "value": 2, + "label": "alien" + } + ] + }, + { + "symbol": "MODEL", + "name": "MODEL", + "index": 5, + "min_value": 0, + "max_value": 6, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "Colorsound Wah" + }, + { + "value": 1, + "label": "Dallas Wah" + }, + { + "value": 2, + "label": "Foxx Wah" + }, + { + "value": 3, + "label": "Jen Wah" + }, + { + "value": 4, + "label": "Maestro Wah" + }, + { + "value": 5, + "label": "SelmerWah" + }, + { + "value": 6, + "label": "Vox Wah V847" + } + ] + }, + { + "symbol": "WET_DRY", + "name": "WET_DRY", + "index": 6, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_compressor#_compressor", + "name": "GxCompressor", + "plugin_type": "CompressorPlugin", + "plugin_display_type": "Compressor", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n\"Compression (or more technically Dynamic range compression) is a subtle effect primarily for electric guitar where the highest and lowest points of the sound wave are \"limited\". This boosts the volume of softer picked notes, while capping the louder ones, giving a more even level of volume. This is frequently used in country music, where fast clean passages can sound uneven unless artificially 'squashed'.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Compression_%28electric_guitar%29\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "RATIO", + "name": "RATIO", + "index": 0, + "min_value": 1, + "max_value": 20, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "KNEE", + "name": "KNEE", + "index": 1, + "min_value": 0, + "max_value": 20, + "default_value": 3, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "index": 2, + "min_value": -96, + "max_value": 10, + "default_value": -20, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE", + "name": "RELEASE", + "index": 3, + "min_value": 0, + "max_value": 10, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK", + "name": "ATTACK", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.00200000009, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_cstb_#_cstb_", + "name": "GxColorSound Tonebender", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "ATTACK", + "name": "ATTACK", + "index": 2, + "min_value": 0, + "max_value": 0.949999988, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "WET_DRY", + "index": 4, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_delay_stereo#_delay_stereo", + "name": "GxDelay-Stereo", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\nA stereo delay plugin with independent delay time and delay gain for each channel. It also has a LFO modulator and two modes: linear and pingpong.\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "mode", + "name": "Mode", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "linear" + }, + { + "value": 1, + "label": "pingpong" + } + ] + }, + { + "symbol": "level_r", + "name": "R Level", + "index": 1, + "min_value": -20, + "max_value": 20, + "default_value": -10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "timt_r", + "name": "R Time", + "index": 2, + "min_value": 1, + "max_value": 5000, + "default_value": 1000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level_l", + "name": "L Level", + "index": 3, + "min_value": -20, + "max_value": 20, + "default_value": -10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "timt_l", + "name": "L Time", + "index": 4, + "min_value": 1, + "max_value": 5000, + "default_value": 1000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "lfo", + "name": "LFO", + "index": 5, + "min_value": 0.200000003, + "max_value": 5, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "link", + "name": "Link (L+R)", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_detune_#_detune_", + "name": "Gxdetune", + "plugin_type": "PitchPlugin", + "plugin_display_type": "Pitch Shifter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DETUNE", + "name": "DETUNE", + "index": 2, + "min_value": -12, + "max_value": 12, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OCTAVE", + "name": "OCTAVE", + "index": 3, + "min_value": 0, + "max_value": 2, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "normal" + }, + { + "value": 1, + "label": "octaveup" + }, + { + "value": 2, + "label": "octavedown" + } + ] + }, + { + "symbol": "COMPENSATE", + "name": "COMPENSATE", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "latency" + }, + { + "value": 1, + "label": "compensate" + } + ] + }, + { + "symbol": "LATENCY", + "name": "LATENCY", + "index": 5, + "min_value": 0, + "max_value": 2, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "highquality" + }, + { + "value": 1, + "label": "lowquality" + }, + { + "value": 2, + "label": "realtime" + } + ] + }, + { + "symbol": "WET", + "name": "WET", + "index": 6, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRY", + "name": "DRY", + "index": 7, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LOW", + "name": "LOW", + "index": 8, + "min_value": 0, + "max_value": 2, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MIDDLELOW", + "name": "MIDDLELOW", + "index": 9, + "min_value": 0, + "max_value": 2, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MIDDLETREBLE", + "name": "MIDDLETREBLE", + "index": 10, + "min_value": 0, + "max_value": 2, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TREBLE", + "name": "TREBLE", + "index": 11, + "min_value": 0, + "max_value": 2, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_digital_delay_#_digital_delay_", + "name": "Gxdigital_delay", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "BPM", + "name": "BPM", + "index": 2, + "min_value": 24, + "max_value": 360, + "default_value": 120, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "index": 3, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN", + "name": "GAIN", + "index": 4, + "min_value": 0, + "max_value": 120, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "HIGHPASS", + "name": "HIGHPASS", + "index": 5, + "min_value": 20, + "max_value": 20000, + "default_value": 120, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "HOWPASS", + "name": "HOWPASS", + "index": 6, + "min_value": 20, + "max_value": 20000, + "default_value": 12000, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 7, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MODE", + "name": "MODE", + "index": 8, + "min_value": 0, + "max_value": 3, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "plain" + }, + { + "value": 1, + "label": "presence" + }, + { + "value": 2, + "label": "tape" + }, + { + "value": 3, + "label": "tape2" + } + ] + }, + { + "symbol": "NOTES", + "name": "NOTES", + "index": 9, + "min_value": 1, + "max_value": 18, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Dotted1/2note" + }, + { + "value": 2, + "label": "1/2note" + }, + { + "value": 3, + "label": "1/2notetriplets" + }, + { + "value": 4, + "label": "Dotted1/4note" + }, + { + "value": 5, + "label": "1/4note" + }, + { + "value": 6, + "label": "1/4notetriplets" + }, + { + "value": 7, + "label": "Dotted1/8note" + }, + { + "value": 8, + "label": "1/8note" + }, + { + "value": 9, + "label": "1/8notetriplets" + }, + { + "value": 10, + "label": "Dotted1/16note" + }, + { + "value": 11, + "label": "1/16note" + }, + { + "value": 12, + "label": "1/16notetriplets" + }, + { + "value": 13, + "label": "Dotted1/32note" + }, + { + "value": 14, + "label": "1/32note" + }, + { + "value": 15, + "label": "1/32notetriplets" + }, + { + "value": 16, + "label": "Dotted1/64note" + }, + { + "value": 17, + "label": "1/64note" + }, + { + "value": 18, + "label": "1/64notetriplets" + } + ] + }, + { + "symbol": "SYNC", + "name": "SYNC", + "index": 12, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_digital_delay_st_#_digital_delay_st_", + "name": "Gxdigital_delay_st", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "BPM", + "name": "BPM", + "index": 4, + "min_value": 24, + "max_value": 360, + "default_value": 120, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "index": 5, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN", + "name": "GAIN", + "index": 6, + "min_value": 0, + "max_value": 120, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "HIGHPASS", + "name": "HIGHPASS", + "index": 7, + "min_value": 20, + "max_value": 20000, + "default_value": 120, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "HOWPASS", + "name": "HOWPASS", + "index": 8, + "min_value": 20, + "max_value": 20000, + "default_value": 12000, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 9, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MODE", + "name": "MODE", + "index": 10, + "min_value": 0, + "max_value": 3, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "plain" + }, + { + "value": 1, + "label": "presence" + }, + { + "value": 2, + "label": "tape" + }, + { + "value": 3, + "label": "tape2" + } + ] + }, + { + "symbol": "NOTES", + "name": "NOTES", + "index": 11, + "min_value": 1, + "max_value": 18, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Dotted1/2note" + }, + { + "value": 2, + "label": "1/2note" + }, + { + "value": 3, + "label": "1/2notetriplets" + }, + { + "value": 4, + "label": "Dotted1/4note" + }, + { + "value": 5, + "label": "1/4note" + }, + { + "value": 6, + "label": "1/4notetriplets" + }, + { + "value": 7, + "label": "Dotted1/8note" + }, + { + "value": 8, + "label": "1/8note" + }, + { + "value": 9, + "label": "1/8notetriplets" + }, + { + "value": 10, + "label": "Dotted1/16note" + }, + { + "value": 11, + "label": "1/16note" + }, + { + "value": 12, + "label": "1/16notetriplets" + }, + { + "value": 13, + "label": "Dotted1/32note" + }, + { + "value": 14, + "label": "1/32note" + }, + { + "value": 15, + "label": "1/32notetriplets" + }, + { + "value": 16, + "label": "Dotted1/64note" + }, + { + "value": 17, + "label": "1/64note" + }, + { + "value": 18, + "label": "1/64notetriplets" + } + ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_duck_delay_#_duck_delay_", + "name": "Gxduck_delay", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nThe delayed signal added to output dependent of input signal amplitude. \nIf the input signal is high. The delayed signall turned off, and vise versa.\nThe switching controlled by envelope follower\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "AMOUNT", + "name": "AMOUNT", + "index": 2, + "min_value": 0, + "max_value": 56, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK", + "name": "ATTACK", + "index": 3, + "min_value": 0.0500000007, + "max_value": 0.5, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELESE", + "name": "RELESE", + "index": 5, + "min_value": 0.0500000007, + "max_value": 2, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME", + "name": "TIME", + "index": 6, + "min_value": 1, + "max_value": 2000, + "default_value": 500, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_duck_delay_st_#_duck_delay_st_", + "name": "Gxduck_delay_st", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\nThe delayed signal added to output dependent of input signal amplitude. \nIf the input signal is high. The delayed signall turned off, and vise versa.\nThe switching controlled by envelope follower\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "AMOUNT", + "name": "AMOUNT", + "index": 4, + "min_value": 0, + "max_value": 56, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK", + "name": "ATTACK", + "index": 5, + "min_value": 0.0500000007, + "max_value": 0.5, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "COLORATION", + "name": "COLORATION", + "index": 6, + "min_value": -1, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "EFFECT", + "name": "EFFECT", + "index": 7, + "min_value": -16, + "max_value": 4, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK", + "name": "FEEDBACK", + "index": 8, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PINGPONG", + "name": "PINGPONG", + "index": 9, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE", + "name": "RELEASE", + "index": 10, + "min_value": 0.0500000007, + "max_value": 2, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME", + "name": "TIME", + "index": 11, + "min_value": 1, + "max_value": 2000, + "default_value": 500, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_echo_stereo#_echo_stereo", + "name": "GxEcho-Stereo", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\nA stereo echo plugin with independent delay time and delay volume for each channel. It also has a LFO modulator and two modes: linear and pingpong.\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "mode", + "name": "Mode", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "linear" + }, + { + "value": 1, + "label": "pingpong" + } + ] + }, + { + "symbol": "level_r", + "name": "R Level", + "index": 1, + "min_value": 0, + "max_value": 100, + "default_value": 30, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "timt_r", + "name": "R Time", + "index": 2, + "min_value": 1, + "max_value": 2000, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level_l", + "name": "L Level", + "index": 3, + "min_value": 0, + "max_value": 100, + "default_value": 30, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "timt_l", + "name": "L Time", + "index": 4, + "min_value": 1, + "max_value": 2000, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "lfo", + "name": "LFO", + "index": 5, + "min_value": 0.200000003, + "max_value": 5, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "link", + "name": "Link (L+R)", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_expander#_expander", + "name": "GxExpander", + "plugin_type": "ExpanderPlugin", + "plugin_display_type": "Expander", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n\"The expander is a compressor in reverse. There are two types of expander. In some, signals above the threshold remain at unity gain whereas signals below the threshold are reduced in gain, whereas in others the signal above the threshold also has the gain increased. Therefore you can use an expander as a noise reduction unit. Set the threshold to be just below the level of the player when playing. When the player stops the signal will fall below this threshold and the signal is reduced in gain thus reducing the noise or spill.\"\n\n*Unofficial documentation\n\nsource: http://www.sae.edu/reference_material/audio/pages/Compression.htm\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "RATIO", + "name": "RATIO", + "index": 0, + "min_value": 1, + "max_value": 20, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "KNEE", + "name": "KNEE", + "index": 1, + "min_value": 0, + "max_value": 20, + "default_value": 3, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "index": 2, + "min_value": -96, + "max_value": 10, + "default_value": -40, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE", + "name": "RELEASE", + "index": 3, + "min_value": 0, + "max_value": 10, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK", + "name": "ATTACK", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.00100000005, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_flanger#_flanger", + "name": "GxFlanger", + "plugin_type": "FlangerPlugin", + "plugin_display_type": "Flanger", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n\"Flanging /\u02C8fl\u00E6nd\u0292\u02EA\u01CB/ is an audio effect produced by mixing two identical signals together, one signal delayed by a small and gradually changing period, usually smaller than 20 milliseconds. This produces a swept comb filter effect: peaks and notches are produced in the resulting frequency spectrum, related to each other in a linear harmonic series. Varying the time delay causes these to sweep up and down the frequency spectrum. A flanger is an effects unit that creates this effect.\n\nPart of the output signal is usually fed back to the input (a \"re-circulating delay line\"), producing a resonance effect which further enhances the intensity of the peaks and troughs. The phase of the fed-back signal is sometimes inverted, producing another variation on the flanging sound.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Flanging\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "depth", + "name": "DEPTH", + "index": 0, + "min_value": 0, + "max_value": 5, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "width", + "name": "WIDTH", + "index": 1, + "min_value": 0, + "max_value": 10, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "freq", + "name": "FREQ", + "index": 2, + "min_value": 0.0500000007, + "max_value": 10, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "feedback", + "name": "FEEDBACK", + "index": 3, + "min_value": -0.99000001, + "max_value": 0.99000001, + "default_value": -0.707000017, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "dry_wet", + "name": "WET", + "index": 4, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "mix", + "name": "MIX", + "index": 5, + "min_value": -1, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fumaster_#_fumaster_", + "name": "GxFuzzMaster", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "TONE", + "name": "TONE", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "WET_DRY", + "index": 4, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fuzz_#fuzz_", + "name": "GxFuzz", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\nA Fuzz Effect\n\n*Unofficial documentation\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "INPUT", + "name": "INPUT", + "index": 0, + "min_value": -20, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OUTPUT", + "name": "OUTPUT", + "index": 1, + "min_value": 50, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 2, + "min_value": -3, + "max_value": 100, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TONE", + "name": "TONE", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fuzzface_#_fuzzface_", + "name": "GxFuzzFaceJH2", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "FUZZ", + "name": "FUZZ", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_fuzzfacefm_#_fuzzfacefm_", + "name": "GxFuzzFaceFuller", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FUZZ", + "name": "FUZZ", + "index": 3, + "min_value": 0, + "max_value": 0.99000001, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "INPUT", + "name": "INPUT", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_gcb_95_#_gcb_95_", + "name": "Gxgcb_95", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 2, + "min_value": -20, + "max_value": 4, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "HOTPOTZ", + "name": "WAH", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_graphiceq_#_graphiceq_", + "name": "GxGraphicEQ", + "plugin_type": "EQPlugin", + "plugin_display_type": "Equaliser", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n\"In the graphic equalizer, the input signal is sent to a bank of filters. Each filter passes the portion of the signal present in its own frequency range or band. The amplitude passed by each filter is adjusted using a slide control to boost or cut frequency components passed by that filter. The vertical position of each slider thus indicates the gain applied at that frequency band, so that the knobs resemble a graph of the equalizer's response plotted versus frequency.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Equalization_%28audio%29#Graphic_equalizer\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "G10", + "name": "G10", + "index": 0, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G11", + "name": "G11", + "index": 1, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G1", + "name": "G1", + "index": 2, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G2", + "name": "G2", + "index": 3, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G3", + "name": "G3", + "index": 4, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G4", + "name": "G4", + "index": 5, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G5", + "name": "G5", + "index": 6, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G6", + "name": "G6", + "index": 7, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G7", + "name": "G7", + "index": 8, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G8", + "name": "G8", + "index": 9, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "G9", + "name": "G9", + "index": 10, + "min_value": -30, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_hfb_#_hfb_", + "name": "GxHF_Brightener", + "plugin_type": "EQPlugin", + "plugin_display_type": "Equaliser", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "INTENSITY", + "name": "INTENSITY", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_hogsfoot_#_hogsfoot_", + "name": "GxHogsFoot", + "plugin_type": "FilterPlugin", + "plugin_display_type": "Filter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "WET_DRY", + "index": 3, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_hornet_#_hornet_", + "name": "GxHornet", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "FUZZ", + "name": "FUZZ", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "SUSTAIN", + "name": "SUSTAIN", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_jcm800pre_#_jcm800pre_", + "name": "Gxjcm800pre", + "plugin_type": "AmplifierPlugin", + "plugin_display_type": "Amplifier", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "P6v", + "name": "Pre Amp", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Middle", + "name": "Middle", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Bass", + "name": "Bass", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Treble", + "name": "Treble", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "Presence", + "index": 6, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN", + "name": "Master Volume", + "index": 7, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_jcm800pre_st#_jcm800pre_st", + "name": "Gxjcm800preST", + "plugin_type": "AmplifierPlugin", + "plugin_display_type": "Amplifier", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "P6v", + "name": "Pre Amp", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Middle", + "name": "Middle", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Bass", + "name": "Bass", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Treble", + "name": "Treble", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "Presence", + "index": 8, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN", + "name": "Master Volume", + "index": 9, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_livelooper_#_livelooper_", + "name": "Gxlivelooper", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "clip1", + "name": "clip1", + "index": 2, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clip2", + "name": "clip2", + "index": 3, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clip3", + "name": "clip3", + "index": 4, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clip4", + "name": "clip4", + "index": 5, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clips1", + "name": "clips1", + "index": 6, + "min_value": 0, + "max_value": 100, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clips2", + "name": "clips2", + "index": 7, + "min_value": 0, + "max_value": 100, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clips3", + "name": "clips3", + "index": 8, + "min_value": 0, + "max_value": 100, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "clips4", + "name": "clips4", + "index": 9, + "min_value": 0, + "max_value": 100, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed1", + "name": "speed1", + "index": 10, + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed2", + "name": "speed2", + "index": 11, + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed3", + "name": "speed3", + "index": 12, + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed4", + "name": "speed4", + "index": 13, + "min_value": -0.899999976, + "max_value": 0.899999976, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "gain", + "index": 18, + "min_value": -20, + "max_value": 12, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level1", + "name": "level1", + "index": 19, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level2", + "name": "level2", + "index": 20, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level3", + "name": "level3", + "index": 21, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level4", + "name": "level4", + "index": 22, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "mix", + "name": "mix", + "index": 23, + "min_value": 0, + "max_value": 150, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "play1", + "name": "play1", + "index": 24, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "play2", + "name": "play2", + "index": 25, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "play3", + "name": "play3", + "index": 26, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "play4", + "name": "play4", + "index": 27, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rplay1", + "name": "rplay1", + "index": 28, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rplay2", + "name": "rplay2", + "index": 29, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rplay3", + "name": "rplay3", + "index": 30, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rplay4", + "name": "rplay4", + "index": 31, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rec1", + "name": "rec1", + "index": 36, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rec2", + "name": "rec2", + "index": 37, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rec3", + "name": "rec3", + "index": 38, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "rec4", + "name": "rec4", + "index": 39, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "reset1", + "name": "reset1", + "index": 40, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "reset2", + "name": "reset2", + "index": 41, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "reset3", + "name": "reset3", + "index": 42, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "reset4", + "name": "reset4", + "index": 43, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbcompressor_#_mbcompressor_", + "name": "GxMultiBandCompressor", + "plugin_type": "CompressorPlugin", + "plugin_display_type": "Compressor", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n\"Multiband (also spelled multi-band) compressors can act differently on different frequency bands. The advantage of multiband compression over full-bandwidth (full-band, or single-band) compression is that unneeded audible gain changes or \"pumping\" in other frequency bands is not caused by changing signal levels in a single frequency band.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Dynamic_range_compression#Multiband_compression\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "MODE1", + "name": "MODE1", + "index": 0, + "min_value": 1, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + } + ] + }, + { + "symbol": "MODE2", + "name": "MODE2", + "index": 1, + "min_value": 1, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + } + ] + }, + { + "symbol": "MODE3", + "name": "MODE3", + "index": 2, + "min_value": 1, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + } + ] + }, + { + "symbol": "MODE4", + "name": "MODE4", + "index": 3, + "min_value": 1, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + } + ] + }, + { + "symbol": "MODE5", + "name": "MODE5", + "index": 4, + "min_value": 1, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 1, + "label": "Compress" + }, + { + "value": 2, + "label": "Bypass" + }, + { + "value": 3, + "label": "Mute" + } + ] + }, + { + "symbol": "MAKEUP1", + "name": "MAKEUP1", + "index": 5, + "min_value": -50, + "max_value": 50, + "default_value": 13, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUP2", + "name": "MAKEUP2", + "index": 6, + "min_value": -50, + "max_value": 50, + "default_value": 13, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUP3", + "name": "MAKEUP3", + "index": 7, + "min_value": -50, + "max_value": 50, + "default_value": 13, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUP4", + "name": "MAKEUP4", + "index": 8, + "min_value": -50, + "max_value": 50, + "default_value": 13, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUP5", + "name": "MAKEUP5", + "index": 9, + "min_value": -50, + "max_value": 50, + "default_value": 13, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUPTHRESHOLD1", + "name": "MAKEUPTHRESHOLD1", + "index": 10, + "min_value": 0, + "max_value": 10, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUPTHRESHOLD2", + "name": "MAKEUPTHRESHOLD2", + "index": 11, + "min_value": 0, + "max_value": 10, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUPTHRESHOLD3", + "name": "MAKEUPTHRESHOLD3", + "index": 12, + "min_value": 0, + "max_value": 10, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUPTHRESHOLD4", + "name": "MAKEUPTHRESHOLD4", + "index": 13, + "min_value": 0, + "max_value": 10, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MAKEUPTHRESHOLD5", + "name": "MAKEUPTHRESHOLD5", + "index": 14, + "min_value": 0, + "max_value": 10, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RATIO1", + "name": "RATIO1", + "index": 15, + "min_value": 1, + "max_value": 100, + "default_value": 13, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RATIO2", + "name": "RATIO2", + "index": 16, + "min_value": 1, + "max_value": 100, + "default_value": 10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RATIO3", + "name": "RATIO3", + "index": 17, + "min_value": 1, + "max_value": 100, + "default_value": 4, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RATIO4", + "name": "RATIO4", + "index": 18, + "min_value": 1, + "max_value": 100, + "default_value": 8, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RATIO5", + "name": "RATIO5", + "index": 19, + "min_value": 1, + "max_value": 100, + "default_value": 11, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK1", + "name": "ATTACK1", + "index": 20, + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK2", + "name": "ATTACK2", + "index": 21, + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK3", + "name": "ATTACK3", + "index": 22, + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK4", + "name": "ATTACK4", + "index": 23, + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ATTACK5", + "name": "ATTACK5", + "index": 24, + "min_value": 0.00100000005, + "max_value": 1, + "default_value": 0.0120000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE1", + "name": "RELEASE1", + "index": 25, + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE2", + "name": "RELEASE2", + "index": 26, + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE3", + "name": "RELEASE3", + "index": 27, + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE4", + "name": "RELEASE4", + "index": 28, + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RELEASE5", + "name": "RELEASE5", + "index": 29, + "min_value": 0.00999999978, + "max_value": 10, + "default_value": 1.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "index": 30, + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "index": 31, + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "index": 32, + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "index": 33, + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbdelay_#_mbdelay_", + "name": "GxMultiBandDelay", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DELAY1", + "name": "DELAY1", + "index": 0, + "min_value": 24, + "max_value": 360, + "default_value": 30, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DELAY2", + "name": "DELAY2", + "index": 1, + "min_value": 24, + "max_value": 360, + "default_value": 60, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DELAY3", + "name": "DELAY3", + "index": 2, + "min_value": 24, + "max_value": 360, + "default_value": 90, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DELAY4", + "name": "DELAY4", + "index": 3, + "min_value": 24, + "max_value": 360, + "default_value": 120, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DELAY5", + "name": "DELAY5", + "index": 4, + "min_value": 24, + "max_value": 360, + "default_value": 150, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK1", + "name": "FEEDBACK1", + "index": 5, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK2", + "name": "FEEDBACK2", + "index": 6, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK3", + "name": "FEEDBACK3", + "index": 7, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK4", + "name": "FEEDBACK4", + "index": 8, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FEEDBACK5", + "name": "FEEDBACK5", + "index": 9, + "min_value": 1, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN1", + "name": "GAIN1", + "index": 10, + "min_value": -40, + "max_value": 2, + "default_value": -10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN2", + "name": "GAIN2", + "index": 11, + "min_value": -40, + "max_value": 2, + "default_value": -5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN3", + "name": "GAIN3", + "index": 12, + "min_value": -40, + "max_value": 2, + "default_value": -2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN4", + "name": "GAIN4", + "index": 13, + "min_value": -40, + "max_value": 2, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN5", + "name": "GAIN5", + "index": 14, + "min_value": -40, + "max_value": 2, + "default_value": -10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "index": 15, + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "index": 16, + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "index": 17, + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "index": 18, + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbdistortion_#_mbdistortion_", + "name": "GxMultiBandDistortion", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DRIVE1", + "name": "DRIVE1", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE2", + "name": "DRIVE2", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE3", + "name": "DRIVE3", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.649999976, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE4", + "name": "DRIVE4", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.25, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE5", + "name": "DRIVE5", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN", + "name": "GAIN", + "index": 5, + "min_value": -40, + "max_value": 4, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OFFSET1", + "name": "OFFSET1", + "index": 6, + "min_value": 0, + "max_value": 0.5, + "default_value": 0.170000002, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OFFSET2", + "name": "OFFSET2", + "index": 7, + "min_value": 0, + "max_value": 0.5, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OFFSET3", + "name": "OFFSET3", + "index": 8, + "min_value": 0, + "max_value": 0.5, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OFFSET4", + "name": "OFFSET4", + "index": 9, + "min_value": 0, + "max_value": 0.5, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OFFSET5", + "name": "OFFSET5", + "index": 10, + "min_value": 0, + "max_value": 0.5, + "default_value": 0.170000002, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "index": 11, + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "index": 12, + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "index": 13, + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "index": 14, + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbecho_#_mbecho_", + "name": "GxMultiBandEcho", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "PERCENT1", + "name": "PERCENT1", + "index": 0, + "min_value": 0, + "max_value": 100, + "default_value": 10, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PERCENT2", + "name": "PERCENT2", + "index": 1, + "min_value": 0, + "max_value": 100, + "default_value": 30, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PERCENT3", + "name": "PERCENT3", + "index": 2, + "min_value": 0, + "max_value": 100, + "default_value": 45, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PERCENT4", + "name": "PERCENT4", + "index": 3, + "min_value": 0, + "max_value": 100, + "default_value": 20, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PERCENT5", + "name": "PERCENT5", + "index": 4, + "min_value": 0, + "max_value": 100, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME1", + "name": "TIME1", + "index": 5, + "min_value": 24, + "max_value": 360, + "default_value": 30, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME2", + "name": "TIME2", + "index": 6, + "min_value": 24, + "max_value": 360, + "default_value": 60, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME3", + "name": "TIME3", + "index": 7, + "min_value": 24, + "max_value": 360, + "default_value": 120, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME4", + "name": "TIME4", + "index": 8, + "min_value": 24, + "max_value": 360, + "default_value": 150, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TIME5", + "name": "TIME5", + "index": 9, + "min_value": 24, + "max_value": 360, + "default_value": 240, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B1_B2", + "name": "LOW SHELF", + "index": 10, + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "index": 11, + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "index": 12, + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "index": 13, + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mbreverb_#_mbreverb_", + "name": "GxMultiBandReverb", + "plugin_type": "ReverbPlugin", + "plugin_display_type": "Reverb", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "ROOMSIZE1", + "name": "ROOMSIZE1", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ROOMSIZE2", + "name": "ROOMSIZE2", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ROOMSIZE3", + "name": "ROOMSIZE3", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ROOMSIZE4", + "name": "ROOMSIZE4", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ROOMSIZE5", + "name": "ROOMSIZE5", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B1_B2", + "name": "CROSSOVER_B1_B2", + "index": 7, + "min_value": 20, + "max_value": 20000, + "default_value": 80, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B2_B3", + "name": "CROSSOVER_B2_B3", + "index": 8, + "min_value": 20, + "max_value": 20000, + "default_value": 210, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B3_B4", + "name": "CROSSOVER_B3_B4", + "index": 9, + "min_value": 20, + "max_value": 20000, + "default_value": 1700, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSSOVER_B4_B5", + "name": "CROSSOVER_B4_B5", + "index": 10, + "min_value": 20, + "max_value": 20000, + "default_value": 5000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DAMP1", + "name": "DAMP1", + "index": 11, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DAMP2", + "name": "DAMP2", + "index": 12, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DAMP3", + "name": "DAMP3", + "index": 13, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DAMP4", + "name": "DAMP4", + "index": 14, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DAMP5", + "name": "DAMP5", + "index": 15, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY1", + "name": "WET_DRY1", + "index": 21, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY2", + "name": "WET_DRY2", + "index": 22, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY3", + "name": "WET_DRY3", + "index": 23, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY4", + "name": "WET_DRY4", + "index": 24, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY5", + "name": "WET_DRY5", + "index": 25, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mole_#_mole_", + "name": "GxMole", + "plugin_type": "FilterPlugin", + "plugin_display_type": "Filter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "BOOST", + "name": "BOOST", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "WET_DRY", + "index": 3, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_muff_#_muff_", + "name": "GxMuff", + "plugin_type": "EQPlugin", + "plugin_display_type": "Equaliser", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "TONE", + "name": "TONE", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_mxrdist_#_mxrdist_", + "name": "GxMXR Distortion", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_oc_2_#_oc_2_", + "name": "Gxoc_2", + "plugin_type": "PitchPlugin", + "plugin_display_type": "Pitch Shifter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DIRECT", + "name": "DIRECT", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OCTAVE1", + "name": "OCTAVE1", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "OCTAVE2", + "name": "OCTAVE2", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_phaser#_phaser", + "name": "GxPhaser", + "plugin_type": "PhaserPlugin", + "plugin_display_type": "Phaser", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n\"A phaser is an electronic sound processor used to filter a signal by creating a series of peaks and troughs in the frequency spectrum. The position of the peaks and troughs is typically modulated so that they vary over time, creating a sweeping effect. For this purpose, phasers usually include a low-frequency oscillator.\" Wikipedia\n\n*Unofficial documentation\n\nsource: http://en.wikipedia.org/wiki/Phaser_%28effect%29\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "dry_wet", + "name": "Dry/Wet", + "index": 0, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level", + "name": "LEVEL", + "index": 1, + "min_value": -60, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed", + "name": "SPEED", + "index": 2, + "min_value": 0, + "max_value": 10, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_rangem_#_rangem_", + "name": "GxRangeMaster", + "plugin_type": "FilterPlugin", + "plugin_display_type": "Filter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "BOOST", + "name": "BOOST", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WET_DRY", + "name": "WET_DRY", + "index": 3, + "min_value": 0, + "max_value": 100, + "default_value": 100, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_redeye#bigchump", + "name": "GxRedeye Big Chump", + "plugin_type": "AmplifierPlugin", + "plugin_display_type": "Amplifier", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "Gain", + "name": "Gain", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Tone", + "name": "Tone", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Volume", + "name": "Volume", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Feedback", + "name": "Feedback", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Vibe", + "name": "Vibe", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Speed", + "name": "Speed", + "index": 5, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Intensity", + "name": "Intensity", + "index": 6, + "min_value": 0, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Sinewave", + "name": "Sinewave", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_redeye#chump", + "name": "GxRedeye Chump", + "plugin_type": "AmplifierPlugin", + "plugin_display_type": "Amplifier", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "Gain", + "name": "Gain", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Tone", + "name": "Tone", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Volume", + "name": "Volume", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Feedback", + "name": "Feedback", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Vibe", + "name": "Vibe", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Speed", + "name": "Speed", + "index": 5, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Intensity", + "name": "Intensity", + "index": 6, + "min_value": 0, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Sinewave", + "name": "Sinewave", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_redeye#vibrochump", + "name": "GxRedeye Vibro Chump", + "plugin_type": "AmplifierPlugin", + "plugin_display_type": "Amplifier", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "Gain", + "name": "Gain", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Tone", + "name": "Tone", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Volume", + "name": "Volume", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Feedback", + "name": "Feedback", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Vibe", + "name": "Vibe", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Speed", + "name": "Speed", + "index": 5, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Intensity", + "name": "Intensity", + "index": 6, + "min_value": 0, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "Sinewave", + "name": "Sinewave", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_reverb_stereo#_reverb_stereo", + "name": "GxReverb-Stereo", + "plugin_type": "ReverbPlugin", + "plugin_display_type": "Reverb", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n\"A Reverb simulates the component of sound that results from reflections from surrounding walls or objects. It is in effect a room simulator. Some people think it's just a delay effect with some filters, but it's way more complex than that.\"\n\n*Unofficial documentation\n\nsource: http://audacity.sourceforge.net/manual-1.2/effects_reverb.html\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "dry_wet", + "name": "Dry/Wet", + "index": 0, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "lfo", + "name": "LFO", + "index": 1, + "min_value": 0.200000003, + "max_value": 5, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "roomsize", + "name": "Roomsize", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "damp", + "name": "Damp", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "mode", + "name": "Mode", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "linear" + }, + { + "value": 1, + "label": "pingpong" + } + ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_room_simulator_#_room_simulator_", + "name": "Gxroom_simulator", + "plugin_type": "ReverbPlugin", + "plugin_display_type": "Reverb", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "EFFECT", + "name": "EFFECT", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PREDELAYMS", + "name": "PREDELAYMS", + "index": 3, + "min_value": 1, + "max_value": 200, + "default_value": 20, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RT", + "name": "RT", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.300000012, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ROOMSIZE", + "name": "ROOMSIZE", + "index": 5, + "min_value": 0, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRYWET", + "name": "DRYWET", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_scream_#_scream_", + "name": "GxScreamingBird", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "SCREAM", + "name": "SCREAM", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_shimmizita_#_shimmizita_", + "name": "Gxshimmizita", + "plugin_type": "ReverbPlugin", + "plugin_display_type": "Reverb", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "CONTROL", + "name": "CONTROL", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DEPTH", + "name": "DEPTH", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRYWET", + "name": "DRYWET", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "ENVELOPE", + "name": "ENVELOPE", + "index": 7, + "min_value": 0.100000001, + "max_value": 3, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "F1", + "name": "F1", + "index": 8, + "min_value": 50, + "max_value": 1000, + "default_value": 200, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "F2", + "name": "F2", + "index": 9, + "min_value": 1500, + "max_value": 23520, + "default_value": 6000, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MODE", + "name": "MODE", + "index": 10, + "min_value": -3, + "max_value": 3, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PSDRYWET", + "name": "PSDRYWET", + "index": 11, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "SHIFT", + "name": "SHIFT", + "index": 12, + "min_value": -6, + "max_value": 6, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "SPEED", + "name": "SPEED", + "index": 13, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "T60DS", + "name": "T60DS", + "index": 14, + "min_value": 1, + "max_value": 8, + "default_value": 3, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "T60M", + "name": "T60M", + "index": 15, + "min_value": 1, + "max_value": 8, + "default_value": 2, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_studiopre#studiopre", + "name": "Gx Studio Preamp Mono", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nBased on simple Alembic F-2B vstudio preamp\n2 sections of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "bright", + "name": "Bright", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "volume", + "name": "Volume", + "index": 1, + "min_value": 0, + "max_value": 20, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "bass", + "name": "Bass", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "middle", + "name": "Middle", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "treble", + "name": "Treble", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_studiopre_st#studiopre_st", + "name": "Gx Studio Preamp Stereo", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\nBased on simple Alembic F-2B vstudio preamp\n2 sectionos of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "bright_l", + "name": "Bright_L", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "volume_l", + "name": "Volume_L", + "index": 1, + "min_value": 0, + "max_value": 20, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "bass_l", + "name": "Bass_L", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "middle_l", + "name": "Middle_L", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "treble_l", + "name": "Treble_L", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "bright_r", + "name": "Bright_R", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "volume_r", + "name": "Volume_R", + "index": 6, + "min_value": 0, + "max_value": 20, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "bass_r", + "name": "Bass_R", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "middle_r", + "name": "Middle_R", + "index": 8, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "treble_r", + "name": "Treble_R", + "index": 9, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_susta_#_susta_", + "name": "GxSustainer", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "SUSTAIN", + "name": "SUSTAIN", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VOLUME", + "name": "VOLUME", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_switched_tremolo_#_switched_tremolo_", + "name": "Gxswitched_tremolo", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "DEPTH", + "name": "DEPTH", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FREQ0", + "name": "FREQ0", + "index": 3, + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FREQ1", + "name": "FREQ1", + "index": 4, + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FREQ2", + "name": "FREQ2", + "index": 5, + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FREQ3", + "name": "FREQ3", + "index": 6, + "min_value": 0.25, + "max_value": 15, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "STEPS", + "name": "STEPS", + "index": 7, + "min_value": 1, + "max_value": 4, + "default_value": 4, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "SWITCHFREQ", + "name": "SWITCHFREQ", + "index": 8, + "min_value": 0.25, + "max_value": 5, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_tremolo#_tremolo", + "name": "GxTremolo", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nModel of a vactrol tremolo unit by \"transmogrify\"\n** c.f. http://sourceforge.net/apps/phpbb/guitarix/viewtopic.php?f=7&t=44&p=233&hilit=transmogrifox#p233\n** http://transmogrifox.webs.com/vactrol.m\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "dry_wet", + "name": "Dry/Wet", + "index": 0, + "min_value": 0, + "max_value": 100, + "default_value": 50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "mode", + "name": "Mode", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "triangle" + }, + { + "value": 1, + "label": "sine" + } + ] + }, + { + "symbol": "depth", + "name": "Depth", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "freq", + "name": "Freq", + "index": 3, + "min_value": 0.100000001, + "max_value": 50, + "default_value": 5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_vibe_#_vibe_", + "name": "Gxvibe", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "WIDTH", + "name": "WIDTH", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DEPTH", + "name": "DEPTH", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.370000005, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WETDRY", + "name": "WETDRY", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FB", + "name": "FB", + "index": 3, + "min_value": -1, + "max_value": 1, + "default_value": -0.600000024, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TEMPO", + "name": "TEMPO", + "index": 4, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 4.4000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DF", + "name": "DF", + "index": 7, + "min_value": -0.5, + "max_value": 0.5, + "default_value": 0.109999999, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PAN", + "name": "PAN", + "index": 8, + "min_value": -1, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CROSS", + "name": "CROSS", + "index": 9, + "min_value": -1, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_vibe_#_vibe_mono", + "name": "GxvibeMono", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "WIDTH", + "name": "WIDTH", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DEPTH", + "name": "DEPTH", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.370000005, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "WETDRY", + "name": "WETDRY", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FB", + "name": "FB", + "index": 3, + "min_value": -1, + "max_value": 1, + "default_value": -0.600000024, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TEMPO", + "name": "TEMPO", + "index": 4, + "min_value": 0.100000001, + "max_value": 10, + "default_value": 4.4000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_w20#w20", + "name": "Gx w20", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nBased on simple w20 F-2B vstudio preamp\n2 sectionos of 12AX7 together with tonestack and volume\nThis is an identical circuit apart from coupling caps whcih could do with filters\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "gain", + "name": "Gain", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level", + "name": "Level", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gx_zita_rev1_stereo#_zita_rev1_stereo", + "name": "GxZita_rev1-Stereo", + "plugin_type": "ReverbPlugin", + "plugin_display_type": "Reverb", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "level", + "name": "LEVEL", + "index": 0, + "min_value": -70, + "max_value": 40, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "EQ2_FREQ", + "name": "EQ2_FREQ", + "index": 1, + "min_value": 160, + "max_value": 10000, + "default_value": 1500, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "EQ1_LEVEL", + "name": "EQ1_LEVEL", + "index": 2, + "min_value": -15, + "max_value": 15, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "EQ1_FREQ", + "name": "EQ1_FREQ", + "index": 3, + "min_value": 40, + "max_value": 2500, + "default_value": 315, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "IN_DELAY", + "name": "IN_DELAY", + "index": 4, + "min_value": 20, + "max_value": 100, + "default_value": 60, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LOW_RT60", + "name": "LOW_RT60", + "index": 5, + "min_value": 1, + "max_value": 8, + "default_value": 3, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LF_X", + "name": "LF_X", + "index": 6, + "min_value": 50, + "max_value": 1000, + "default_value": 200, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "HF_DAMPING", + "name": "HF_DAMPING", + "index": 7, + "min_value": 1500, + "max_value": 23520, + "default_value": 6000, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "MID_RT60", + "name": "MID_RT60", + "index": 8, + "min_value": 1, + "max_value": 8, + "default_value": 2, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRY_WET_MIX", + "name": "DRY_WET_MIX", + "index": 9, + "min_value": -1, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "EQ2_LEVEL", + "name": "EQ2_LEVEL", + "index": 10, + "min_value": -15, + "max_value": 15, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxautowah#autowah", + "name": "GxAutoWah", + "plugin_type": "FilterPlugin", + "plugin_display_type": "Filter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nAnalog wah emulation of the classic Dunlop Crybaby (*), in a auto-wah version.\n\n(*) 'Other product names modeled in this software are trademarks of their respective companies that do not endorse and are not associated or affiliated with MOD.\nDunlop Crybaby is trademark or trade name of other manufacturer and was used merely to identify the product whose sound was reviewed in the creation of this product.\nAll other trademarks are the property of their respective holders.'\n\n*Unofficial documentation\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxautowah#wah", + "name": "GxWah", + "plugin_type": "FilterPlugin", + "plugin_display_type": "Filter", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nAnalog wah emulation of the classic Dunlop Crybaby (*).\n\n(*) 'Other product names modeled in this software are trademarks of their respective companies that do not endorse and are not associated or affiliated with MOD.\nDunlop Crybaby is trademark or trade name of other manufacturer and was used merely to identify the product whose sound was reviewed in the creation of this product.\nAll other trademarks are the property of their respective holders.'\n\n*Unofficial documentation\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "fslider1_", + "name": "Wah", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxbooster#booster", + "name": "GxBooster", + "plugin_type": "UtilityPlugin", + "plugin_display_type": "Utility", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nA 2 band boost plugin. With this plugin you can boost the high and the low frequencies independently.\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "fslider0_", + "name": "H Level", + "index": 0, + "min_value": 0.5, + "max_value": 20, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "fslider1_", + "name": "B Level", + "index": 1, + "min_value": 0.5, + "max_value": 20, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxechocat#echocat", + "name": "GxEchoCat", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nA tape delay simulation plugin.\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "drive", + "name": "Drive", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "swell", + "name": "Swell", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "sustain", + "name": "Sustain", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "Gain", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "bpm", + "name": "BPM", + "index": 4, + "min_value": 24, + "max_value": 360, + "default_value": 120, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "head1", + "name": "Head 1", + "index": 5, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ ] + }, + { + "symbol": "head2", + "name": "Head 2", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ ] + }, + { + "symbol": "head3", + "name": "Head 3", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxmetal_amp#metal_amp", + "name": "GxMetalAmp", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "TONE", + "name": "TONE", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 1, + "min_value": 1, + "max_value": 20, + "default_value": 10.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PREGAIN", + "name": "PREGAIN", + "index": 2, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN1", + "name": "GAIN1", + "index": 3, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxmetal_head#metal_head", + "name": "GxMetalHead", + "plugin_type": "SimulatorPlugin", + "plugin_display_type": "Simulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "TONE", + "name": "TONE", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "DRIVE", + "name": "DRIVE", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.319999993, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PREGAIN", + "name": "PREGAIN", + "index": 2, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN1", + "name": "GAIN1", + "index": 3, + "min_value": -20, + "max_value": 20, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtape#tape", + "name": "GxTape", + "plugin_type": "Plugin", + "plugin_display_type": "Plugin", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "on", + "name": "On", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "drive", + "name": "Drive", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "wowdepth", + "name": "WowDepth", + "index": 2, + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "wowfreq", + "name": "WowFreq", + "index": 3, + "min_value": 0, + "max_value": 4, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "flutdepth", + "name": "FlutterDepth", + "index": 4, + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "flutfreq", + "name": "FluterFreq", + "index": 5, + "min_value": 4, + "max_value": 60, + "default_value": 4, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "hiss", + "name": "Hiss", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "type", + "name": "Type", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed", + "name": "Speed", + "index": 8, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "Gain", + "index": 9, + "min_value": -20, + "max_value": 10, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtape_st#tape", + "name": "Gx Tape Stereo", + "plugin_type": "Plugin", + "plugin_display_type": "Plugin", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 2, + "audio_outputs": 2, + "description": "", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "on", + "name": "On", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "drive", + "name": "Drive", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "wowdepth", + "name": "WowDepth", + "index": 2, + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "wowfreq", + "name": "WowFreq", + "index": 3, + "min_value": 0, + "max_value": 4, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "flutdepth", + "name": "FlutterDepth", + "index": 4, + "min_value": 0, + "max_value": 0.0299999993, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "flutfreq", + "name": "FluterFreq", + "index": 5, + "min_value": 4, + "max_value": 60, + "default_value": 4, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "hiss", + "name": "Hiss", + "index": 6, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "type", + "name": "Type", + "index": 7, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed", + "name": "Speed", + "index": 8, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "Gain", + "index": 9, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtilttone#tilttone", + "name": "GxTiltTone", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\nSimple Tilt tone control\n\nThe tilt control imposes a shelving function, which attenuates half of frequency band and augments the other half. In other words, it is special type of a tone control that, unlike the typical tone control that boosts or cuts just the highs or mids or lows, shifts both highs and lows at once. \n\n*Unofficial documentation\n\nsource: http://www.tubecad.com/2013/06/blog0266.htm\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "body", + "name": "Bpdy", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "tone", + "name": "Tone", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "drive", + "name": "Drive", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level", + "name": "Level", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxts9#ts9sim", + "name": "GxTubeScreamer", + "plugin_type": "DistortionPlugin", + "plugin_display_type": "Distortion", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\nAnalog distortion emulation of the classic Ibanez TS-9 (*)\n\n(*) 'Other product names modeled in this software are trademarks of their respective companies that do not endorse and are not associated or affiliated with MOD.\nIbanez TS-9 is trademark or trade name of other manufacturer and was used merely to identify the product whose sound was reviewed in the creation of this product.\nAll other trademarks are the property of their respective holders.'\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "fslider0_", + "name": "Level", + "index": 0, + "min_value": -20, + "max_value": 4, + "default_value": -16, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "fslider1_", + "name": "Tone", + "index": 1, + "min_value": 100, + "max_value": 1000, + "default_value": 400, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "fslider2_", + "name": "Drive", + "index": 2, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubedelay#tubedelay", + "name": "GxTubeDelay", + "plugin_type": "DelayPlugin", + "plugin_display_type": "Delay", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "drive", + "name": "Drive", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "delay", + "name": "Delay", + "index": 1, + "min_value": 1, + "max_value": 2500, + "default_value": 160, + "is_logarithmic": true, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "feedback", + "name": "Feedback", + "index": 2, + "min_value": 0.00999999978, + "max_value": 1, + "default_value": 0.00999999978, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "level", + "name": "Level", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "Gain", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubetremelo#tubetremelo", + "name": "GxTubeTremelo", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nModel of a vactrol tremolo unit by \"transmogrify\"\nc.f. http://sourceforge.net/apps/phpbb/guitarix/viewtopic.php?f=7&t=44&p=233&hilit=transmogrifox#p233\nhttp://transmogrifox.webs.com/vactrol.m\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "sinewave", + "name": "SineWave", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ ] + }, + { + "symbol": "depth", + "name": "Depth", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed", + "name": "Speed", + "index": 2, + "min_value": 0.100000001, + "max_value": 14, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "drive", + "name": "Drive", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.5, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "Gain", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.200000003, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtubevibrato#tubevibrato", + "name": "GxTubeVibrato", + "plugin_type": "ModulatorPlugin", + "plugin_display_type": "Modulator", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\nAttempt at a true vibrato\nAnd it works well!\nSounds very sweet with tubes wrapped\n\n*Unofficial documentation\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "sinewave", + "name": "SineWave", + "index": 0, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "depth", + "name": "Depth", + "index": 1, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "speed", + "name": "Speed", + "index": 2, + "min_value": 0.100000001, + "max_value": 14, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "drive", + "name": "Drive", + "index": 3, + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "gain", + "name": "Gain", + "index": 4, + "min_value": 0, + "max_value": 1, + "default_value": 0.100000001, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://guitarix.sourceforge.net/plugins/gxtuner#tuner", + "name": "GxTuner", + "plugin_type": "AnalyserPlugin", + "plugin_display_type": "Analyser", + "author_name": "Guitarix team", + "author_homepage": "", + "audio_inputs": 1, + "audio_outputs": 1, + "description": "\n\n...\n\n", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ + { + "symbol": "REFFREQ", + "name": "REFFREQ", + "index": 1, + "min_value": 427, + "max_value": 453, + "default_value": 440, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "TUNER_MODE", + "name": "Tuner Mode", + "index": 2, + "min_value": 0, + "max_value": 54, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "(Chromatic)" + }, + { + "value": 1, + "label": "Standard/E" + }, + { + "value": 2, + "label": "Standard/Es" + }, + { + "value": 3, + "label": "Open E" + }, + { + "value": 4, + "label": "Drop D" + }, + { + "value": 5, + "label": "Half Step Down" + }, + { + "value": 6, + "label": "Full Step Down" + }, + { + "value": 7, + "label": "1 and 1/2 Steps Down" + }, + { + "value": 8, + "label": "Double Drop D" + }, + { + "value": 9, + "label": "Drop C" + }, + { + "value": 10, + "label": "Drop C#" + }, + { + "value": 11, + "label": "Drop B" + }, + { + "value": 12, + "label": "Drop A#" + }, + { + "value": 13, + "label": "Drop A" + }, + { + "value": 14, + "label": "Open D" + }, + { + "value": 15, + "label": "Open D Minor" + }, + { + "value": 16, + "label": "Open G" + }, + { + "value": 17, + "label": "Open G Minor" + }, + { + "value": 18, + "label": "Open C" + }, + { + "value": 19, + "label": "Open C#" + }, + { + "value": 20, + "label": "Open C Minor" + }, + { + "value": 21, + "label": "Open E7" + }, + { + "value": 22, + "label": "Open E Minor7" + }, + { + "value": 23, + "label": "Open G Major7" + }, + { + "value": 24, + "label": "Open A Minor" + }, + { + "value": 25, + "label": "Open A Minor7" + }, + { + "value": 26, + "label": "Open A" + }, + { + "value": 27, + "label": "C Tuning" + }, + { + "value": 28, + "label": "C# Tuning" + }, + { + "value": 29, + "label": "Bb Tuning" + }, + { + "value": 30, + "label": "A to A (Baritone)" + }, + { + "value": 31, + "label": "Open Dsus2" + }, + { + "value": 32, + "label": "Open Gsus2" + }, + { + "value": 33, + "label": "G6" + }, + { + "value": 34, + "label": "Overtone" + }, + { + "value": 35, + "label": "Pentatonic" + }, + { + "value": 36, + "label": "Minor Third" + }, + { + "value": 37, + "label": "Major Third" + }, + { + "value": 38, + "label": "All Fourths" + }, + { + "value": 39, + "label": "Augmented Fourths" + }, + { + "value": 40, + "label": "Slow Motion" + }, + { + "value": 41, + "label": "Admiral" + }, + { + "value": 42, + "label": "Buzzard" + }, + { + "value": 43, + "label": "Face" + }, + { + "value": 44, + "label": "Four and Twenty" + }, + { + "value": 45, + "label": "Ostrich" + }, + { + "value": 46, + "label": "Capo 200" + }, + { + "value": 47, + "label": "Balalaika" + }, + { + "value": 48, + "label": "Cittern One" + }, + { + "value": 49, + "label": "Cittern Two" + }, + { + "value": 50, + "label": "Dobro" + }, + { + "value": 51, + "label": "Lefty" + }, + { + "value": 52, + "label": "Mandoguitar" + }, + { + "value": 53, + "label": "Rusty Cage" + }, + { + "value": 54, + "label": "Hardcore" + } + ] + }, + { + "symbol": "TEMPERAMENT", + "name": "TEMPERAMENT", + "index": 3, + "min_value": 0, + "max_value": 2, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "THRESHOLD", + "name": "THRESHOLD", + "index": 4, + "min_value": -60, + "max_value": 4, + "default_value": -50, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "RESET", + "name": "RESET", + "index": 6, + "min_value": -10, + "max_value": 10, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "LEVEL", + "name": "LEVEL", + "index": 7, + "min_value": -60, + "max_value": 4, + "default_value": -45, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "CHANNEL", + "name": "CHANNELL", + "index": 8, + "min_value": 0, + "max_value": 16, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": true, + "scale_points": [ + { + "value": 0, + "label": "0" + }, + { + "value": 1, + "label": "1" + }, + { + "value": 2, + "label": "2" + }, + { + "value": 3, + "label": "3" + }, + { + "value": 4, + "label": "4" + }, + { + "value": 5, + "label": "5" + }, + { + "value": 6, + "label": "6" + }, + { + "value": 7, + "label": "7" + }, + { + "value": 8, + "label": "8" + }, + { + "value": 9, + "label": "9" + }, + { + "value": 10, + "label": "10" + }, + { + "value": 11, + "label": "11" + }, + { + "value": 12, + "label": "12" + }, + { + "value": 13, + "label": "13" + }, + { + "value": 14, + "label": "14" + }, + { + "value": 15, + "label": "15" + }, + { + "value": 16, + "label": "16" + } + ] + }, + { + "symbol": "MIDI_ON", + "name": "MIDI_ON", + "index": 9, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "FASTNOTE", + "name": "FASTNOTE", + "index": 10, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "PITCHBEND", + "name": "PITCHBEND", + "index": 11, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "SINGLENOTE", + "name": "SINGLENOTE", + "index": 12, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "BPM", + "name": "BPM", + "index": 13, + "min_value": 0, + "max_value": 360, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VELOCITY", + "name": "VELOCITY", + "index": 14, + "min_value": 0, + "max_value": 127, + "default_value": 64, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "VERIFY", + "name": "VERIFY", + "index": 15, + "min_value": 1, + "max_value": 12, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GATE", + "name": "GATE", + "index": 16, + "min_value": 0, + "max_value": 1, + "default_value": 0, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": true, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "SYNTHFREQ", + "name": "SYNTHFREQ", + "index": 17, + "min_value": 30, + "max_value": 1000, + "default_value": 220, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + }, + { + "symbol": "GAIN", + "name": "GAIN", + "index": 18, + "min_value": 0, + "max_value": 1, + "default_value": 1, + "is_logarithmic": false, + "display_priority": -1, + "range_steps": 0, + "integer_property": false, + "enumeration_property": false, + "scale_points": [ ] + } + ] + }, + { + "uri": "http://lv2plug.in/plugins/eg-echo", + "name": "Object Serialization Tester", + "plugin_type": "UtilityPlugin", + "plugin_display_type": "Utility", + "author_name": "Robin Davies", + "author_homepage": "http://two-play.com/", + "audio_inputs": 0, + "audio_outputs": 0, + "description": "Plugin used to test text conversion of patch property objects.", + "has_midi_input": 0, + "has_midi_output": 0, + "controls": [ ] + } + ] \ No newline at end of file diff --git a/react/react_info.txt b/react/react_info.txt new file mode 100644 index 0000000..5771b93 --- /dev/null +++ b/react/react_info.txt @@ -0,0 +1,28 @@ +found 8 vulnerabilities (4 moderate, 4 high) + run `npm audit fix` to fix them, or `npm audit` for details + +Created git commit. + +Success! Created my-app at /home/patch/src/piddle/react/my-app +Inside that directory, you can run several commands: + + npm start + Starts the development server. + + npm run build + Bundles the app into static files for production. + + npm test + Starts the test runner. + + npm run eject + Removes this tool and copies build dependencies, configuration files + and scripts into the app directory. If you do this, you canât go back! + +We suggest that you begin by typing: + + cd my-app + npm start + +Happy hacking! + diff --git a/react/src/AboutDialog.tsx b/react/src/AboutDialog.tsx new file mode 100644 index 0000000..0b11b62 --- /dev/null +++ b/react/src/AboutDialog.tsx @@ -0,0 +1,223 @@ +import React, { SyntheticEvent, Component } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel'; +import { TransitionProps } from '@material-ui/core/transitions/transition'; +import Slide from '@material-ui/core/Slide'; +import Dialog from '@material-ui/core/Dialog'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import Divider from '@material-ui/core/Divider'; +import JackHostStatus from './JackHostStatus'; + + +interface AboutDialogProps extends WithStyles { + open: boolean; + onClose: () => void; + + +}; + +interface AboutDialogState { + jackStatus?: JackHostStatus; +}; + + +const styles = (theme: Theme) => createStyles({ + dialogAppBar: { + position: 'relative', + top: 0, left: 0 + }, + dialogTitle: { + marginLeft: theme.spacing(2), + flex: 1, + }, + sectionHead: { + marginLeft: 24, + marginRight: 24, + marginTop: 16, + paddingBottom: 12 + + }, + textBlock: { + marginLeft: 24, + marginRight: 24, + marginTop: 16, + paddingBottom: 0, + opacity: 0.95 + + }, + textBlockIndented: { + marginLeft: 40, + marginRight: 24, + marginTop: 16, + paddingBottom: 0, + opacity: 0.95 + + }, + + setting: { + minHeight: 64, + width: "100%", + textAlign: "left", + paddingLeft: 22, + paddingRight: 22 + }, + primaryItem: { + + }, + secondaryItem: { + + } + + +}); + + +const Transition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + + +const AboutDialog = withStyles(styles, { withTheme: true })( + + class extends Component { + + model: PiPedalModel; + + + + constructor(props: AboutDialogProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.handleDialogClose = this.handleDialogClose.bind(this); + this.state = { + jackStatus: undefined + + }; + } + + mounted: boolean = false; + subscribed: boolean = false; + + tick() { + if (this.model.state.get() === State.Ready) { + this.model.getJackStatus() + .then(jackStatus => { + this.setState({jackStatus: jackStatus}); + }) + .catch(error => { /* ignore*/ }); + } + } + + timerHandle?: NodeJS.Timeout; + + updateNotifications() { + let subscribed = this.mounted && this.props.open; + if (subscribed !== this.subscribed) { + if (subscribed) { + this.timerHandle = setInterval(() => this.tick(), 1000); + } else { + if (this.timerHandle) { + clearInterval(this.timerHandle); + this.timerHandle = undefined; + } + } + this.subscribed = subscribed; + } + } + + + componentDidMount() { + this.mounted = true; + this.updateNotifications(); + } + componentWillUnmount() { + this.mounted = false; + this.updateNotifications(); + } + componentDidUpdate() { + this.updateNotifications(); + } + + handleDialogClose(e: SyntheticEvent) { + this.props.onClose(); + } + + + render() { + let classes = this.props.classes; + + return ( + { this.props.onClose() }} TransitionComponent={Transition}> + +
+
+ + + + + + + About + + + +
+
+
+ + PiPedal + {(this.model.serverVersion? this.model.serverVersion.serverVersion : "") + + (this.model.serverVersion?.debug ? " (Debug)": "")} + + + + Copyright © 2021 Robin Davies. All rights reserved. + + + + JACK AUDIO STATUS + +
+ { + JackHostStatus.getDisplayView("",this.state.jackStatus) + } +
+ + + LEGAL NOTICES + + + Pi Pedal uses the following open-source components. + + + TBD + + +
+
+
+
+ + ); + + } + + } + +); + +export default AboutDialog; \ No newline at end of file diff --git a/react/src/App.css b/react/src/App.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/react/src/App.css @@ -0,0 +1 @@ + diff --git a/react/src/App.test.tsx b/react/src/App.test.tsx new file mode 100644 index 0000000..2a68616 --- /dev/null +++ b/react/src/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/react/src/App.tsx b/react/src/App.tsx new file mode 100644 index 0000000..a41a438 --- /dev/null +++ b/react/src/App.tsx @@ -0,0 +1,830 @@ +import { SyntheticEvent } from 'react'; +import { ThemeProvider } from '@material-ui/styles'; +import { createMuiTheme } from '@material-ui/core/styles'; + +import './App.css'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import Typography from '@material-ui/core/Typography'; +import { createStyles, withStyles, WithStyles } from '@material-ui/core/styles'; +import IconButton from '@material-ui/core/IconButton'; +import MenuButton from '@material-ui/icons/Menu'; +import { TemporaryDrawer } from './TemporaryDrawer'; +import { Theme } from '@material-ui/core/styles/createMuiTheme'; +import FullscreenIcon from '@material-ui/icons/Fullscreen'; +import FullscreenExitIcon from '@material-ui/icons/FullscreenExit'; +import List from '@material-ui/core/List'; +import Divider from '@material-ui/core/Divider'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import { OnChangedHandler } from './ObservableProperty'; +import ErrorOutlineIcon from '@material-ui/icons/Error'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import Button from '@material-ui/core/Button'; +import PresetSelector from './PresetSelector'; +import SettingsDialog from './SettingsDialog'; +import AboutDialog from './AboutDialog'; +import BankDialog from './BankDialog'; + +import { PiPedalModelFactory, PiPedalModel, State } from './PiPedalModel'; +import MainPage from './MainPage'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import ListSubheader from '@material-ui/core/ListSubheader'; +import { BankIndex, BankIndexEntry } from './Banks'; +import RenameDialog from './RenameDialog'; +import JackStatusView from './JackStatusView'; + +const theme = createMuiTheme({ + palette: { + primary: { + main: "#324c6c" + } + // secondary: { + // main: "#00E676" + // } + } +}); + +const appStyles = ({ palette, spacing, mixins }: Theme) => createStyles({ + loadingContent: { + display: "block", + position: "absolute", + minHeight: "10em", + left: "0px", + top: "0px", + width: "100%", + height: "100%", + background: "#DDD", + opacity: "0.95", + justifyContent: "center", + textAlign: "center", + zIndex: 2010 + }, + errorContent: { + display: "flex", + flexDirection: "column", + justifyContent: "center", + flexWrap: "nowrap", + alignItems: "center", + position: "fixed", + minHeight: "10em", + left: "0px", + top: "0px", + width: "100%", + height: "100%", + color: "#444", + zIndex: 2000 + }, + errorContentMask: { + position: "absolute", left: 0, top: 0, + width: "100%", height: "100%", + background: "#BBB", + opacity: 0.95, + zIndex: 1999 + }, + errorText: { + marginTop: 0, + padding: 0, + marginBottom: 12, + fontWeight: 500, + fontSize: "13pt", + maxWidth: 250, + opacity: 1, + zIndex: 2010, + }, + progressText: { + marginTop: 0, + fontWeight: 500, + fontSize: "13pt", + maxWidth: 250, + opacity: 1, + zIndex: 2010, + paddingTop: 12, + }, + + errorMessageBox: { + flex: "0 0 auto", + width: 300, + marginLeft: "auto", + marginRight: "auto", + zIndex: 2010 + + + }, + errorMessage: { + color: '#000', + textAlign: "left", + zIndex: 2010 + + }, + loadingBox: { + position: "relative", + top: "20%", + width: "120px", + color: "#888", + marginLeft: "auto", + marginRight: "auto", + // border: "3px solid #888", + borderRadius: "12px", + padding: "12px", + justifyContent: "center", + textAlign: "center", + opacity: 0.8, + zIndex: 2010 + + }, + loadingBoxItem: { + justifyContent: "center", + textAlign: "center", + zIndex: 2010 + + }, + + + toolBarContent: + { + position: "absolute", top: 0, width: "100%" + }, + + toolBarSpacer: + { + position: "relative", flex: "0 0 auto" + }, + + + mainFrame: { + overflow: "hidden", + display: "flex", + flexFlow: "column", + flex: "1 1 100%" + }, + + toolbarSizingPosition: { + flexGrow: 0, + flexShrink: 1, + width: "100%", + flexBasis: "auto" + }, + mainSizingPosition: { + overflow: "hidden", + flex: "1 1 auto" + }, + + heroContent: { + backgroundColor: palette.background.paper, + position: "relative", + height: "100%", + width: "100%" + }, + + drawerItem: { + width: 350, + background: "#FF8080" + }, + drawerItemFullWidth: { + width: 'auto', + }, + + icon: { + marginRight: spacing(2), + }, + + heroButtons: { + marginTop: spacing(4), + }, + cardGrid: { + paddingTop: spacing(8), + paddingBottom: spacing(8), + }, + card: { + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + cardMedia: { + paddingTop: '56.25%', // 16:9 + }, + cardContent: { + flexGrow: 1, + }, + footer: { + backgroundColor: palette.background.paper, + padding: spacing(6), + }, +}); + + +function supportsFullScreen(): boolean { + let doc: any = window.document; + let docEl: any = doc.documentElement; + var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen; + return (!!requestFullScreen); + +} + +function setFullScreen(value: boolean) { + let doc: any = window.document; + let docEl: any = doc.documentElement; + + var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen; + var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen; + + if (!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) { + requestFullScreen.call(docEl); + } + else { + cancelFullScreen.call(doc); + } +} + + +function preventDefault(e: SyntheticEvent): void { + e.stopPropagation(); + e.preventDefault(); +} + +type AppState = { + isDrawerOpen: boolean; + errorMessage: string; + displayState: State; + + canFullScreen: boolean; + isFullScreen: boolean; + tinyToolBar: boolean; + alertDialogOpen: boolean; + alertDialogMessage: string; + isSettingsDialogOpen: boolean; + isDebug: boolean; + + renameBankDialogOpen: boolean; + saveBankAsDialogOpen: boolean; + + aboutDialogOpen: boolean; + bankDialogOpen: boolean; + editBankDialogOpen: boolean; + + + presetName: string; + presetChanged: boolean; + banks: BankIndex; + bankDisplayItems: number; +}; +interface AppProps extends WithStyles { +} + +const App = withStyles(appStyles)(class extends ResizeResponsiveComponent { + // Before the component mounts, we initialise our state + + model_: PiPedalModel; + errorChangeHandler_: OnChangedHandler; + stateChangeHandler_: OnChangedHandler; + + constructor(props: AppProps) { + super(props); + this.model_ = PiPedalModelFactory.getInstance(); + + this.state = { + isDrawerOpen: false, + errorMessage: this.model_.errorMessage.get(), + displayState: this.model_.state.get(), + canFullScreen: supportsFullScreen(), + isFullScreen: !!document.fullscreenElement, + tinyToolBar: false, + alertDialogOpen: false, + alertDialogMessage: "", + presetName: this.model_.presets.get().getSelectedText(), + isSettingsDialogOpen: false, + isDebug: true, + presetChanged: this.model_.presets.get().presetChanged, + banks: this.model_.banks.get(), + renameBankDialogOpen: false, + saveBankAsDialogOpen: false, + aboutDialogOpen: false, + bankDialogOpen: false, + editBankDialogOpen: false, + bankDisplayItems: 5 + + }; + + this.errorChangeHandler_ = this.setErrorMessage.bind(this); + this.stateChangeHandler_ = this.setDisplayState.bind(this); + this.presetChangedHandler = this.presetChangedHandler.bind(this); + this.alertMessageChangedHandler = this.alertMessageChangedHandler.bind(this); + this.handleCloseAlert = this.handleCloseAlert.bind(this); + this.banksChangedHandler = this.banksChangedHandler.bind(this); + + } + + onOpenBank(bankId: number) { + this.model_.openBank(bankId) + .catch((error) => this.model_.showAlert(error)); + + } + + handleSaveBankAsOk(newName: string) { + let currentName = this.model_.banks.get().getSelectedEntryName(); + if (currentName === newName) { + this.setState({ + renameBankDialogOpen: false, + saveBankAsDialogOpen: false + }); + return; + + } + + if (this.model_.banks.get().nameExists(newName)) { + this.model_.showAlert("A bank by that name already exists."); + return; + } + this.setState({ + renameBankDialogOpen: false, + saveBankAsDialogOpen: false + }); + this.model_.saveBankAs(this.model_.banks.get().selectedBank, newName) + .catch((error) => { + this.model_.showAlert(error); + }); + + } + handleBankRenameOk(newName: string) { + let currentName = this.model_.banks.get().getSelectedEntryName(); + if (currentName === newName) { + this.setState({ + renameBankDialogOpen: false, + saveBankAsDialogOpen: false + }); + return; + + } + + if (this.model_.banks.get().nameExists(newName)) { + this.model_.showAlert("A bank by that name already exists."); + return; + } + this.setState({ + renameBankDialogOpen: false + }); + this.model_.renameBank(this.model_.banks.get().selectedBank, newName) + .catch((error) => { + this.model_.showAlert(error); + }); + + } + handleSettingsDialogClose() { + this.setState({ + isSettingsDialogOpen: false + }); + } + handleDrawerSettingsClick() { + this.setState({ + isDrawerOpen: false, + isSettingsDialogOpen: true + }); + + } + + handleDrawerManageBanks() { + this.setState({ + isDrawerOpen: false, + bankDialogOpen: true, + editBankDialogOpen: true + }); + + } + handleDrawerSelectBank() { + this.setState({ + isDrawerOpen: false, + bankDialogOpen: true, + editBankDialogOpen: false + }); + + } + + handleDrawerAboutClick() { + this.setState({ + aboutDialogOpen: true + }); + + } + handleDrawerRenameBank() { + this.setState({ + isDrawerOpen: false, + renameBankDialogOpen: true, + saveBankAsDialogOpen: false + }); + + } + handleDrawerSaveBankAs() { + this.setState({ + isDrawerOpen: false, + renameBankDialogOpen: false, + saveBankAsDialogOpen: true + }); + } + + + handleCloseAlert(e?: any, reason?: any) { + this.model_.alertMessage.set(""); + } + banksChangedHandler() { + this.setState({ + banks: this.model_.banks.get() + }); + } + presetChangedHandler() { + let presets = this.model_.presets.get(); + + this.setState({ + presetName: presets.getSelectedText(), + presetChanged: presets.presetChanged + }); + } + toggleFullScreen(): void { + setFullScreen(this.state.isFullScreen); + this.setState({ isFullScreen: !this.state.isFullScreen }); + } + componentDidMount() { + + super.componentDidMount(); + + window.addEventListener("beforeunload", (e) => { + e.preventDefault(); + if (this.model_.state.get() === State.Ready) + { + e.returnValue = "Are you sure you want to leave this page?"; + return "Are you sure you want to leave this page?"; + } + }); + + this.model_.errorMessage.addOnChangedHandler(this.errorChangeHandler_); + this.model_.state.addOnChangedHandler(this.stateChangeHandler_); + this.model_.pedalBoard.addOnChangedHandler(this.presetChangedHandler); + this.model_.alertMessage.addOnChangedHandler(this.alertMessageChangedHandler); + this.model_.banks.addOnChangedHandler(this.banksChangedHandler); + this.alertMessageChangedHandler(); + } + + + updateOverscroll(): void { + if (this.model_.serverVersion) { + // no pull-down refresh on android devices once we're ready (unless we're debug) + let preventOverscroll = + this.model_.state.get() === State.Ready + && !this.model_.serverVersion.debug; + + let overscrollBehavior = preventOverscroll ? "none" : "auto"; + document.body.style.overscrollBehavior = overscrollBehavior; + } + } + + componentDidUpdate() { + } + + componentWillUnmount() { + super.componentWillUnmount(); + this.model_.errorMessage.removeOnChangedHandler(this.errorChangeHandler_); + this.model_.state.removeOnChangedHandler(this.stateChangeHandler_); + this.model_.pedalBoard.removeOnChangedHandler(this.presetChangedHandler); + this.model_.banks.addOnChangedHandler(this.banksChangedHandler); + + } + + alertMessageChangedHandler() { + let message = this.model_.alertMessage.get(); + if (message === "") { + this.setState({ alertDialogOpen: false }); + // leave the message intact so the dialog can fade. + } else { + this.setState({ + alertDialogOpen: true, + alertDialogMessage: message + }); + } + + } + updateResponsive() { + // functional, but disabled. + // let tinyToolBar_ = this.windowSize.height < 600; + // this.setState({ tinyToolBar: tinyToolBar_ }); + + let height = this.windowSize.height; + + const ENTRY_HEIGHT = 48; + // ENTRY_HEIGHT*6 +K = 727 from observation. + const K = 450; + + let bankEntries = Math.floor((height-K)/ENTRY_HEIGHT); + if (bankEntries < 1) bankEntries = 1; + if (bankEntries > 7) bankEntries = 7; + this.setState({ bankDisplayItems: bankEntries }); + + } + onWindowSizeChanged(width: number, height: number): void { + super.onWindowSizeChanged(width, height); + this.updateResponsive(); + } + + + setErrorMessage(message: string): void { + this.setState({ errorMessage: message }); + } + setDisplayState(newState: State): void { + this.updateOverscroll(); + + this.setState({ displayState: newState }); + } + + showDrawer() { + this.setState({ isDrawerOpen: true }) + } + hideDrawer() { + this.setState({ isDrawerOpen: false }) + } + shortBankList(banks: BankIndex): BankIndexEntry[] { + let n = this.state.bankDisplayItems; + let entries = banks.entries; + if (entries.length < n + 1) { // +1 for the .... entry. + return entries; + } + let result: BankIndexEntry[] = []; + let selectedIndex = -1; + for (let i = 0; i < entries.length; ++i) { + if (entries[i].instanceId === banks.selectedBank) { + selectedIndex = i; + break; + } + } + if (n > entries.length) n = entries.length; + if (selectedIndex > n) { + for (let i = 0; i < n - 1; ++i) { + result.push(entries[i]); + } + result.push(entries[selectedIndex]); + } else { + for (let i = 0; i < n; ++i) { + result.push(entries[i]); + } + } + return result; + } + render() { + + const { classes } = this.props; + + let shortBankList = this.shortBankList(this.state.banks); + let showBankSelectDialog = shortBankList.length !== this.state.banks.entries.length; + + + return ( + +
{ + if (!this.model_.serverVersion?.debug??false) + { + e.preventDefault(); e.stopPropagation(); + } + }} + > + + {(!this.state.tinyToolBar) ? + ( + + + { this.showDrawer() }} + > + + +
+
+ +
+
+ {this.state.canFullScreen && + { this.toggleFullScreen(); }}> + {this.state.isFullScreen ? ( + + ) : ( + + + )} + + + } + + + ) : ( +
+ { this.showDrawer() }} + > + + + {this.state.canFullScreen && ( + { this.toggleFullScreen(); }}> + {this.state.isFullScreen ? ( + + ) : ( + + + )} + + + )} +
+ )} + { this.hideDrawer(); }} > + Banks + }> + { + shortBankList.map((bank) => { + return ( + this.onOpenBank(bank.instanceId)} + > + + + + + ); + }) + } + { + showBankSelectDialog && ( + this.handleDrawerSelectBank()} + > + + + + + + ) + } + + + + { this.handleDrawerRenameBank() }}> + + + + { this.handleDrawerSaveBankAs() }} > + + + + + + { this.handleDrawerManageBanks(); }}> + + + + + + + + + { this.handleDrawerSettingsClick() }}> + + + + + + { this.handleDrawerAboutClick() }}> + + + + + + + + + {!this.state.tinyToolBar && ( + + )} +
+
+
+ {(this.state.displayState !== State.Loading) && ( + + )} +
+ +
+
+ this.setState({ bankDialogOpen: false })} /> + this.setState({ aboutDialogOpen: false })} /> + this.handleSettingsDialogClose()} /> + { + this.setState({ + renameBankDialogOpen: false, + saveBankAsDialogOpen: false + }) + }} + onOk={(text: string) => { + if (this.state.renameBankDialogOpen) { + this.handleBankRenameOk(text); + } else if (this.state.saveBankAsDialogOpen) { + this.handleSaveBankAsOk(text); + } + } + } + /> + + + + + { + this.model_.alertMessage.get() + } + + + + + + + +
+
+ +
+
+ +
+ + Reconnecting... + +
+
+
+
+
 
+
+
+ +
+
+

+ Error: {this.state.errorMessage} +

+
+
+ + +
+ +
+ +
 
+ +
+
+
+
+
+ +
+ + Loading... + +
+
+ +
+ + ); + } +} +); + +export default App; diff --git a/react/src/BankDialog.tsx b/react/src/BankDialog.tsx new file mode 100644 index 0000000..d538950 --- /dev/null +++ b/react/src/BankDialog.tsx @@ -0,0 +1,470 @@ +import React, { Component } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { BankIndexEntry, BankIndex } from './Banks'; +import Button from "@material-ui/core/Button"; +import ButtonBase from "@material-ui/core/ButtonBase"; +import { TransitionProps } from '@material-ui/core/transitions/transition'; +import Slide from '@material-ui/core/Slide'; +import Dialog from '@material-ui/core/Dialog'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import DraggableGrid, { ScrollDirection } from './DraggableGrid'; + +import SelectHoverBackground from './SelectHoverBackground'; +import CloseIcon from '@material-ui/icons/Close'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import EditIcon from '@material-ui/icons/Edit'; +import RenameDialog from './RenameDialog'; + +interface BankDialogProps extends WithStyles { + show: boolean; + isEditDialog: boolean; + onDialogClose: () => void; + +}; + +interface BankDialogState { + banks: BankIndex; + + showActionBar: boolean; + + selectedItem: number; + + filenameDialogOpen: boolean; + filenameSaveAs: boolean; + +}; + + +const styles = (theme: Theme) => createStyles({ + dialogAppBar: { + position: 'relative', + top: 0, left: 0 + }, + dialogActionBar: { + position: 'relative', + top: 0, left: 0, + background: "black" + }, + dialogTitle: { + marginLeft: theme.spacing(2), + flex: 1, + }, + itemFrame: { + display: "flex", + flexDirection: "row", + flexWrap: "nowrap", + width: "100%", + height: "56px", + alignItems: "center", + textAlign: "left", + justifyContent: "center", + paddingLeft: 8 + }, + iconFrame: { + flex: "0 0 auto", + + }, + itemIcon: { + width: 24, height: 24, margin: 12, opacity: 0.6 + }, + itemLabel: { + flex: "1 1 1px", + marginLeft: 8 + } + +}); + + +const Transition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const ActionBarTransition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + + +const BankDialog = withStyles(styles, { withTheme: true })( + + class extends Component { + + model: PiPedalModel; + + + + constructor(props: BankDialogProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.handleDialogClose = this.handleDialogClose.bind(this); + let banks = this.model.banks.get(); + this.state = { + banks: banks, + showActionBar: false, + selectedItem: banks.selectedBank, + filenameDialogOpen: false, + filenameSaveAs: false + }; + this.handleBanksChanged = this.handleBanksChanged.bind(this); + this.handlePopState = this.handlePopState.bind(this); + + } + + selectItemAtIndex(index: number) + { + let instanceId = this.state.banks.entries[index].instanceId; + this.setState({selectedItem: instanceId}); + } + isEditMode() { + return this.state.showActionBar || this.props.isEditDialog; + } + + handleBanksChanged() { + let banks = this.model.banks.get(); + + if (!banks.areEqual(this.state.banks,false)) // avoid a bunch of peculiar effects if we update while a drag is in progress + { + // if we don't have a valid selection, then use the current preset. + if (this.state.banks.getEntry(this.state.selectedItem) == null) + { + this.setState({ banks: banks, selectedItem: banks.selectedBank}); + } else { + this.setState({ banks: banks }); + } + } + } + + mounted: boolean = false; + + hasHooks: boolean = false; + + stateWasPopped: boolean = false; + handlePopState(e: any): any { + let state: any = e.state; + if (!state || !state.bankDialog) + { + this.stateWasPopped = true; + this.props.onDialogClose(); + } + } + + updateBackButtonHooks() : void { + let wantHooks = this.mounted && this.props.show; + if (wantHooks !== this.hasHooks) + { + this.hasHooks = wantHooks; + + if (this.hasHooks) + { + this.stateWasPopped = false; + window.addEventListener("popstate",this.handlePopState); + // eslint-disable-next-line no-restricted-globals + let newState: any = history.state; + if (!newState) + { + newState = {}; + } + newState.bankDialog = true; + // eslint-disable-next-line no-restricted-globals + history.pushState( + newState, + "PiPedal - Banks", + "#Banks" + ); + } else { + window.removeEventListener("popstate",this.handlePopState); + if (!this.stateWasPopped) + { + // eslint-disable-next-line no-restricted-globals + history.back(); + } + // eslint-disable-next-line no-restricted-globals + history.replaceState({},"PiPedal","#"); + } + + } + } + + + componentDidUpdate() + { + this.updateBackButtonHooks(); + } + componentDidMount() { + this.model.banks.addOnChangedHandler(this.handleBanksChanged); + this.handleBanksChanged(); + // scroll selected item into view. + this.mounted = true; + this.updateBackButtonHooks(); + } + componentWillUnmount() { + this.model.banks.removeOnChangedHandler(this.handleBanksChanged); + this.mounted = false; + this.updateBackButtonHooks(); + } + + getSelectedIndex() { + let instanceId = this.isEditMode() ? this.state.selectedItem: this.state.banks.selectedBank; + let banks = this.state.banks; + for (let i = 0; i < banks.entries.length; ++i) { + if (banks.entries[i].instanceId === instanceId) return i; + } + return -1; + } + + handleDeleteClick() { + if (!this.state.selectedItem) return; + let selectedItem = this.state.selectedItem; + if (selectedItem !== -1) { + this.model.deleteBankItem(selectedItem) + .then((newSelection: number) => { + this.setState({ + selectedItem: newSelection + }); + }) + .catch((error) => { + this.model.showAlert(error); + }); + } + } + handleDialogClose() + { + this.props.onDialogClose(); + } + + handleItemClick(instanceId: number): void { + if (this.isEditMode()) { + this.setState({ selectedItem: instanceId }); + } else { + this.model.openBank(instanceId); + this.props.onDialogClose(); + } + } + showActionBar(show: boolean): void { + this.setState({ showActionBar: show }); + + } + + + mapElement(el: any): React.ReactNode { + let presetEntry = el as BankIndexEntry; + let classes = this.props.classes; + let selectedItem = this.isEditMode() ? this.state.selectedItem : this.state.banks.selectedBank; + return ( +
+ + this.handleItemClick(presetEntry.instanceId)} + > + +
+
+ +
+
+ + {presetEntry.name} + +
+
+
+
+ + ); + } + + moveElement(from: number, to: number): void { + let newBanks = this.state.banks.clone(); + newBanks.moveBank(from, to); + this.setState({ + banks: newBanks, + selectedItem: newBanks.entries[to].instanceId + }); + this.model.moveBank(from, to) + .catch((error)=> { + this.model.showAlert(error); + }); + } + + getSelectedName(): string { + let item = this.state.banks.getEntry(this.state.selectedItem); + if (item) return item.name; + return ""; + } + + handleRenameClick() { + let item = this.state.banks.getEntry(this.state.selectedItem); + if (item) { + this.setState({ filenameDialogOpen: true, filenameSaveAs: false }); + } + } + handleRenameOk(text: string) { + let item = this.state.banks.getEntry(this.state.selectedItem); + if (!item) return; + if (item.name !== text) { + if (this.state.banks.hasName(text)) + { + this.model.showAlert("A bank with that name already exists."); + } + this.model.renameBank(this.state.selectedItem, text) + .catch((error) => { + this.onError(error); + }); + } + + this.setState({ filenameDialogOpen: false }); + } + handleSaveAsOk(text: string) { + let item = this.state.banks.getEntry(this.state.selectedItem); + if (item) + { + if (item.name !== text) { + if (this.state.banks.hasName(text)) + { + this.model.showAlert("A bank with that name already exists."); + return; + } + this.model.saveBankAs(this.state.selectedItem, text) + .then((newSelection) => { + this.setState({selectedItem: newSelection}); + }) + .catch((error) => { + this.onError(error); + }); + } + } + this.setState({ filenameDialogOpen: false }); + } + + handleCopy() { + let item = this.state.banks.getEntry(this.state.selectedItem); + if (item) { + this.setState({ filenameDialogOpen: true, filenameSaveAs: true }); + } + } + + onError(error: string): void { + this.model?.showAlert(error); + } + + + + render() { + let classes = this.props.classes; + + let actionBarClass = this.props.isEditDialog ? classes.dialogAppBar : classes.dialogActionBar; + let defaultSelectedIndex = this.getSelectedIndex(); + + return ( + { this.handleDialogClose() }} TransitionComponent={Transition}> +
+
+ + + + + + + Banks + + this.showActionBar(true)} > + + + + + { e.stopPropagation(); e.preventDefault(); }} + > + + {(!this.props.isEditDialog) ? ( + this.showActionBar(false)} aria-label="close"> + + + ) : ( + + + + + )} + + Banks + + {(this.state.banks.getEntry(this.state.selectedItem) != null) + && ( + +
+ + + { this.setState({ filenameDialogOpen: false }) }} + onOk={(text: string) => { + if (this.state.filenameSaveAs) + { + this.handleSaveAsOk(text); + } else { + this.handleRenameOk(text); + } + } + } + /> + this.handleDeleteClick()} > + Delete + +
+ ) + } +
+ +
+
+
+ this.showActionBar(true)} + canDrag={this.isEditMode()} + onDragStart={(index,x,y)=> {this.selectItemAtIndex(index) } } + moveElement={(from, to) => { this.moveElement(from, to); }} + scroll={ScrollDirection.Y} + defaultSelectedIndex={defaultSelectedIndex} + > + { + this.state.banks.entries.map((element) => + { + return this.mapElement(element); + }) + } + +
+
+
+ + ); + + } + + } + +); + +export default BankDialog; \ No newline at end of file diff --git a/react/src/Banks.tsx b/react/src/Banks.tsx new file mode 100644 index 0000000..1443e81 --- /dev/null +++ b/react/src/Banks.tsx @@ -0,0 +1,95 @@ + +export class BankIndexEntry { + deserialize(input: any) : BankIndexEntry { + this.instanceId = input.instanceId; + this.name = input.name; + return this; + + } + + areEqual(other: BankIndexEntry) : boolean { + return (this.instanceId === other.instanceId) + && (this.name === other.name); + } + static deserialize_array(input: any): BankIndexEntry[] { + let result: BankIndexEntry[] = []; + for (let i = 0; i < input.length; ++i) + { + result.push(new BankIndexEntry().deserialize(input[i])); + } + return result; + + } + instanceId: number = -1; + name: string = ""; +} + +export class BankIndex { + deserialize(input: any) : BankIndex { + this.selectedBank = input.selectedBank; + this.entries = BankIndexEntry.deserialize_array(input.entries); + return this; + } + selectedBank: number = -1; + entries: BankIndexEntry[] = []; + + areEqual(other: BankIndex, includeSelection: boolean): boolean { + if (includeSelection && this.selectedBank !== other.selectedBank) return false; + + if (this.entries.length !== other.entries.length) return false; + + for (let i = 0; i < this.entries.length; ++i) + { + if (!this.entries[i].areEqual(other.entries[i])) return false; + } + + + return true; + + } + + moveBank(from: number, to: number) + { + let t = this.entries[from]; + this.entries.splice(from,1); + this.entries.splice(to,0,t); + + } + + clone(): BankIndex { + return new BankIndex().deserialize(this); + } + + hasName(name: string): boolean { + for (let i = 0; i < this.entries.length; ++i) + { + let entry = this.entries[i]; + if (entry.name === name) { + return true; + } + } + return false; + } + getEntry(instanceId: number): BankIndexEntry | null { + for (let i = 0; i < this.entries.length; ++i) + { + let entry = this.entries[i]; + if (entry.instanceId === instanceId) return entry; + } + return null; + } + getSelectedEntryName(): string { + let entry = this.getEntry(this.selectedBank); + if (!entry) return ""; + return entry.name; + } + nameExists(name: string): boolean { + for (let i = 0; i < this.entries.length; ++i) + { + let entry = this.entries[i]; + if (entry.name === name) return true; + } + return false; + + } +} \ No newline at end of file diff --git a/react/src/ControlViewFactory.tsx b/react/src/ControlViewFactory.tsx new file mode 100644 index 0000000..7bd033a --- /dev/null +++ b/react/src/ControlViewFactory.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; + + +import {PedalBoardItem, PedalBoardSplitItem} from './PedalBoard'; +import PluginControlView from './PluginControlView'; +import SplitControlView from './SplitControlView'; +import Typography from '@material-ui/core/Typography'; +import IControlViewFactory from './IControlViewFactory'; +import ToobInputStageViewFactory from './ToobInputStageView'; +import ToobToneStackViewFactory from './ToobToneStackView'; +import ToobCabSimViewFactory from './ToobCabSimView'; + + +let pluginFactories: IControlViewFactory[] = [ + new ToobInputStageViewFactory(), + new ToobToneStackViewFactory(), + new ToobCabSimViewFactory() +]; + + +export function GetControlView(pedalBoardItem?: PedalBoardItem| null): React.ReactNode +{ + let model: PiPedalModel = PiPedalModelFactory.getInstance(); + + if (!pedalBoardItem) { + return (
); + } + if (pedalBoardItem.isSplit()) + { + return ( + + ); + } else { + for (let i = 0; i < pluginFactories.length; ++i) + { + let factory = pluginFactories[i]; + if (factory.uri === pedalBoardItem.uri) + { + return factory.Create(model,pedalBoardItem); + } + } + let uiPlugin = model.getUiPlugin(pedalBoardItem.uri); + if (!uiPlugin) + { +
+ Missing plugin. + The plugin '{pedalBoardItem.pluginName}' ({pedalBoardItem.uri}) is not currently installed. +
+ } else { + return ( + + ) + } + } +} + diff --git a/react/src/Draggable.tsx b/react/src/Draggable.tsx new file mode 100644 index 0000000..14559e0 --- /dev/null +++ b/react/src/Draggable.tsx @@ -0,0 +1,479 @@ +import { MouseEvent, PointerEvent, ReactNode, Component } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalStateError } from './PiPedalError'; + + +const SELECT_SCALE = 1.5; + +const AUTOSCROLL_TICK_DELAY = 30; +const AUTOSCROLL_THRESHOLD = 48; +const AUTOSCROLL_SCROLL_PER_SECOND = 100; +const AUTOSCROLL_SCROLL_RATE = AUTOSCROLL_SCROLL_PER_SECOND * AUTOSCROLL_TICK_DELAY / 1000; + +const LONG_PRESS_TIME_MS = 250; + +const styles = (theme: Theme) => createStyles({ + frame: { + position: "relative", + margin: "12px" + } +}); + +type Point = { x: number, y: number }; + +export interface DraggableProps extends WithStyles { + onDragStart?: (clientX: number, clientY: number) => void; + onDragMove?: (clientX: number, clientY: number) => void; + onDragEnd?: (clientX: number, clientY: number) => void; + onDragCancel?: (clientX: number, clientY: number) => void; + getScrollContainer: () => HTMLDivElement | null | undefined; + + children?: ReactNode | ReactNode[]; + draggable?: boolean; + + +}; +type DraggableState = { +}; + + +const Draggable = + withStyles(styles, { withTheme: true })( + class extends Component + { + + constructor(props: DraggableProps) { + super(props); + this.onPointerDownCapture = this.onPointerDownCapture.bind(this); + this.onPointerDown = this.onPointerDown.bind(this); + this.onPointerCancel = this.onPointerCancel.bind(this); + this.onPointerMove = this.onPointerMove.bind(this); + this.onPointerUp = this.onPointerUp.bind(this); + this.onClick = this.onClick.bind(this); + this.autoScrollTick = this.autoScrollTick.bind(this); + this.handleTouchMove = this.handleTouchMove.bind(this); + this.handleTouchEnd = this.handleTouchEnd.bind(this); + this.handleTouchStart = this.handleTouchStart.bind(this); + + } + handleTouchStart(e: any) { + if (this.dragStarted) { + //e.preventDefault(); + } + } + handleTouchMove(e: any) { + if (this.dragStarted) { + e.preventDefault(); + } + } + handleTouchEnd(e: any) { + if (this.dragStarted) { + e.preventDefault(); + } + + } + + + isValidPointer(e: PointerEvent): boolean { + if (e.pointerType === "mouse") { + return e.button === 0; + } else if (e.pointerType === "pen") { + return true; + } else if (e.pointerType === "touch") { + return true; + } + return false; + } + + mouseDown: boolean = false; + pointerId: number = 0; + pointerType: string = ""; + + lastOnDragTime: number = 0; + + onClick(e: MouseEvent) { + // if the click event immediately follows drag end, suppress it. + let dt = new Date().getTime() - this.lastOnDragTime; + if (dt < 150) { + e.preventDefault(); + e.stopPropagation(); + } + + } + + componentDidMount() + { + } + componentWillUnmount() + { + + } + isCapturedPointer(e: PointerEvent): boolean { + return this.mouseDown + && e.pointerId === this.pointerId + && e.pointerType === this.pointerType; + + } + + startX: number = 0; + startY: number = 0; + startClientX: number = 0; + startClientY: number = 0; + dragStarted: boolean = false; + savedIndex: string = ""; + lastPointerDown: number = 0; + originalBounds?: DOMRect; + captureElement?: HTMLDivElement; + pointerDownTime: number = 0; + + onPointerDownCapture(e: any) { + // a new pointer down of any type cancels capture + this.cancelDrag(); + e.preventDefault(); + e.stopPropagation(); + } + longPressTimer?: NodeJS.Timeout = undefined; + + longPressTimerTick() { + if (this.pointerType === "touch") { + if (navigator.vibrate) { + navigator.vibrate([10]); + } + if (!this.dragStarted) { + this.dragTarget!.style.transform = "scale(" + SELECT_SCALE + ")"; + this.dragTarget!.style.zIndex = "3"; + } + + this.startDrag(); + } + } + + + cancelDrag() { + window.removeEventListener("touchmove", this.handleTouchMove); + window.removeEventListener("touchend", this.handleTouchEnd); + if (this.longPressTimer) { + clearTimeout(this.longPressTimer); + this.longPressTimer = undefined; + } + + this.stopAutoScroll(); + if (this.dragStarted && this.captureElement) { + try { + this.captureElement.releasePointerCapture(this.pointerId); + } catch (error) + { + // throws if we've already lost it. + } + + } + this.dragStarted = false; + if (this.captureElement) { + this.clearDragTransform(this.captureElement); + this.captureElement = undefined; + } + this.mouseDown = false; + + document.body.removeEventListener("pointerdown", this.onPointerDownCapture, true); + this.dragTarget = undefined; + } + + + dragTarget?: HTMLDivElement; + + onPointerDown(e: PointerEvent): void { + + if (this.props.draggable !== undefined && !this.props.draggable) return; + + // any new pointer down cancles a drag in progress. + this.cancelDrag(); + + // avoid 2nd click of a double click (which is difficult to cancel) + let timeMs = new Date().getTime(); + if (timeMs - this.lastPointerDown < 300) { + this.lastPointerDown = timeMs; + return; + } + this.lastPointerDown = timeMs; + + + if (!this.mouseDown && this.isValidPointer(e)) { + + this.longPressTimer = setTimeout(() => this.longPressTimerTick(), LONG_PRESS_TIME_MS); + + this.dragTarget = e.currentTarget as HTMLDivElement; + document.body.addEventListener("pointerdown", this.onPointerDownCapture, true); + this.captureElement = e.currentTarget; + // e.currentTarget.setPointerCapture(e.pointerId); + + this.mouseDown = true; + this.dragStarted = false; + this.startX = e.clientX; + this.startY = e.clientY; + this.startClientX = e.clientX; + this.startClientY = e.clientY; + + this.pointerId = e.pointerId; + this.pointerType = e.pointerType; + this.savedIndex = e.currentTarget.style.zIndex; + if (this.pointerType !== "touch") { + this.dragTarget.style.transform = "scale(" + SELECT_SCALE + ")"; + this.dragTarget.style.zIndex = "3"; + } + } + } + + clearDragTransform(element: HTMLDivElement): void { + element.style.transform = ""; + element.style.zIndex = this.savedIndex; + } + + onPointerCancel(e: PointerEvent) { + if (this.isCapturedPointer(e)) { + this.cancelDrag(); + if (this.props.onDragCancel) { + this.props.onDragCancel(e.clientX, e.clientY); + } + } + } + + onPointerUp(e: PointerEvent) { + if (this.isCapturedPointer(e)) { + e.preventDefault(); + e.stopPropagation(); + if (this.dragStarted) { + this.lastOnDragTime = new Date().getTime(); + if (this.props.onDragEnd) { + this.props.onDragEnd(e.clientX, e.clientY); + } + } + this.cancelDrag(); + + + } + } + + dragThresholdExceeded(e: PointerEvent) { + let dx = e.clientX - this.startX; + let dy = e.clientY - this.startY; + let d2 = dx * dx + dy * dy; + if (this.pointerType === "touch") { + return false; // wait for long press. + } + + let DRAG_THRESHOLD = 5; + if (this.pointerType === "touch") { + DRAG_THRESHOLD = 15; + } + let result = (d2 > DRAG_THRESHOLD * DRAG_THRESHOLD); + return result; + } + + lastX: number = 0; + lastY: number = 0; + + translateViewPortPoint(fromElement: HTMLElement, toElement: HTMLElement, pt: Point): Point { + let rcFrom = fromElement.getBoundingClientRect(); + let rcTo = toElement.getBoundingClientRect(); + + return { + x: pt.x + rcFrom.left + fromElement.scrollLeft - rcTo.left - toElement.scrollLeft, + y: pt.y + rcFrom.top + fromElement.scrollTop - rcTo.top - toElement.scrollTop + + }; + } + translateViewPortRect(fromElement: HTMLElement, toElement: HTMLElement, rect: DOMRect): DOMRect { + let rcFrom = fromElement.getBoundingClientRect(); + let rcTo = toElement.getBoundingClientRect(); + + return new DOMRect( + rect.x + rcFrom.left - fromElement.scrollLeft - rcTo.left + toElement.scrollLeft, + rect.y + rcFrom.top - fromElement.scrollTop - rcTo.top + toElement.scrollTop, + rect.width, + rect.height); + } + + + makeTransform(targetElement: HTMLElement, clientX: number, clientY: number): string { + let scrollContainer = this.getScrollContainer(); + if (scrollContainer && this.originalBounds) { + // the bounds of the translated element must COMPLETELY fit within the scroll range of the container. + let newLocation = new DOMRect( + this.originalBounds.x + clientX - this.startX, + this.originalBounds.y + clientY - this.startY, + this.originalBounds.width, + this.originalBounds.height); + + + if (newLocation.x < 0) { + clientX -= newLocation.x; + } else if (newLocation.right >= scrollContainer.scrollWidth) { + clientX -= newLocation.right - scrollContainer.scrollWidth; + } + if (newLocation.top < 0) { + clientY -= newLocation.top; + } else if (newLocation.bottom > scrollContainer.scrollHeight) { + clientY -= newLocation.bottom - scrollContainer.scrollHeight; + } + + } + return "translate(" + (clientX - this.startX) + "px," + (clientY - this.startY) + "px) scale(" + SELECT_SCALE + ")"; + + } + + createOriginalBounds() { + // bounds of the target element, in ScrollContainer coordinates. + let rcTarget = this.dragTarget!.getBoundingClientRect(); + rcTarget.x = 0; + rcTarget.y = 0; + + let scrollContainer = this.props.getScrollContainer(); + if (!scrollContainer) { + throw new PiPedalStateError("ScrollContainer reference not valid."); + } + return this.translateViewPortRect(this.dragTarget!, scrollContainer, rcTarget); + } + + startDrag() { + window.addEventListener("touchmove", this.handleTouchMove, { passive: false }); + window.addEventListener("touchend", this.handleTouchEnd, { passive: false }); + + + this.dragStarted = true; + if (this.props.onDragStart) { + this.props.onDragStart(this.startX, this.startY); + } + this.dragTarget!.setPointerCapture(this.pointerId); + this.originalBounds = this.createOriginalBounds(); + + } + + onPointerMove(e: PointerEvent): void { + if (this.isCapturedPointer(e)) { + if (!this.dragStarted && this.dragThresholdExceeded(e)) { + this.startDrag(); + + + } + if (this.dragStarted) { + this.lastX = e.clientX; + this.lastY = e.clientY; + e.currentTarget.style.transform = this.makeTransform(e.currentTarget, e.clientX, e.clientY); + e.stopPropagation(); + e.preventDefault(); + + if (this.props.onDragMove) { + this.props.onDragMove(e.clientX, e.clientY); + } + + this.checkForAutoScroll(e.currentTarget); + } + } + } + autoScrollTimer?: number; + + autoScrollTick(currentTarget: HTMLElement, dx: number, dy: number) { + if (!this.mouseDown) return; + let scrollContainer = this.getScrollContainer(); + if (scrollContainer) { + let tx = scrollContainer.scrollLeft; + let ty = scrollContainer.scrollTop; + scrollContainer.scrollBy(dx, dy); + this.startX -= (scrollContainer.scrollLeft - tx); + this.startY -= (scrollContainer.scrollTop - ty); + + currentTarget.style.transform = this.makeTransform(currentTarget, this.lastX, this.lastY); + + this.checkForAutoScroll(currentTarget); + } + } + stopAutoScroll() { + if (this.autoScrollTimer) { + cancelAnimationFrame(this.autoScrollTimer); + this.autoScrollTimer = undefined; + } + } + startAutoScroll(scrollContainer: HTMLElement, dx: number, dy: number) { + this.stopAutoScroll(); + + this.autoScrollTimer = requestAnimationFrame( + () => { this.autoScrollTick(scrollContainer, dx, dy) }); + } + + checkForAutoScroll(currentTarget: HTMLElement) { + let scrollContainer = this.getScrollContainer(); + if (!scrollContainer) { + this.stopAutoScroll(); + return; + } + + + let scrollContainerRect = scrollContainer.getBoundingClientRect(); + + let dy: number = 0; + let dx: number = 0; + + if (this.lastX < scrollContainerRect.x + AUTOSCROLL_THRESHOLD) { + dx = -AUTOSCROLL_SCROLL_RATE; + if (dx < -scrollContainer.scrollLeft) { + dx = -scrollContainer.scrollLeft; + } + } else if (this.lastX >= scrollContainerRect.right - AUTOSCROLL_THRESHOLD) { + dx = AUTOSCROLL_SCROLL_RATE; + let maxScroll = Math.max(scrollContainer.scrollWidth - scrollContainer.clientWidth, 0); + if (dx > maxScroll) dx = maxScroll; + } + if (this.lastY < scrollContainerRect.top) { + dy = -AUTOSCROLL_SCROLL_RATE; + if (dy < -scrollContainer.scrollTop) dy = -scrollContainer.scrollTop; + } else if (this.lastY >= scrollContainerRect.top - AUTOSCROLL_THRESHOLD) { + dy = AUTOSCROLL_SCROLL_RATE; + let maxScroll = Math.max(scrollContainer.scrollHeight - scrollContainer.clientHeight); + if (dy > maxScroll) dy = maxScroll; + } + + if (dx === 0 && dy === 0) { + this.stopAutoScroll(); + return; + } else { + this.startAutoScroll(currentTarget, dx, dy); + } + + + + } + + getScrollContainer(): HTMLDivElement | null { + if (this.props.getScrollContainer) { + let t = this.props.getScrollContainer(); + if (!t) return null; + return t; + } + return null; + } + + + + + render() { + return ( +
{ e.preventDefault(); e.stopPropagation(); }} + onClick={this.onClick} + > + { + this.props.children + } +
+ ) + } + + } + ); + +export default Draggable; diff --git a/react/src/DraggableGrid.tsx b/react/src/DraggableGrid.tsx new file mode 100644 index 0000000..9e57cac --- /dev/null +++ b/react/src/DraggableGrid.tsx @@ -0,0 +1,922 @@ +import React, { MouseEvent, PointerEvent, Component } from 'react'; +import { createStyles, Theme } from '@material-ui/core/styles'; +import { Property } from "csstype"; +import { nullCast} from './Utility' + +const SELECT_SCALE = 1.0; + +const AUTOSCROLL_TICK_DELAY = 30; +const AUTOSCROLL_THRESHOLD = 48; +const AUTOSCROLL_SCROLL_PER_SECOND = 300; +const AUTOSCROLL_SCROLL_RATE = AUTOSCROLL_SCROLL_PER_SECOND * AUTOSCROLL_TICK_DELAY / 1000; + +const LONG_PRESS_TIME_MS = 250; + + +const ANIMATION_DURATION_MS = 100; + + + +class AnimationData { + constructor(element: HTMLElement, originalPosition: DOMRect) { + this.element = element; + this.originalPosition = originalPosition; + this.fromY = this.toY = this.currentY = this.originalPosition.y; + this.key = (element as any)["key"]; + } + key: any; + element: HTMLElement; + originalPosition: DOMRect; + fromY: number; + toY: number; + currentY: number; + + animating: boolean = false; + + setPosition(y: number) + { + this.fromY = this.toY; + this.toY = y; + this.animating = true; + } + snapToPosition() { + this.fromY = this.toY; + this.currentY = this.toY; + this.animating = true; + } + +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const styles = (theme: Theme) => createStyles({ + frame: { + position: "relative", + margin: "12px", + background: theme.palette.background.paper + } +}); + +type Point = { x: number, y: number }; + +export enum ScrollDirection { + None, X, Y +} +export interface DraggableGridProps +{ + fullWidth?: boolean; // defaults to true + fullHeight?: boolean; // defaults to true. + onDragStart?: (itemIndex: number, clientX: number, clientY: number) => void; + onDragMove?: (currentItemIndex: number, clientX: number, clientY: number) => void; + onDragEnd?: (fromIndex: number, toIndex: number, clientX: number, clientY: number) => void; + onDragCancel?: (clientX: number, clientY: number) => void; + + defaultSelectedIndex?: number; + + onLongPress?: (itemIndex: number) => void; + + canDrag?: boolean; + + children: React.ReactNode[]; + + moveElement: (from: number, to: number) => void; + scroll: ScrollDirection; + +}; + +type DraggableGridState = { + indexToSelect?: number; +}; + + + +const DraggableGrid = + ( + class extends Component + { + refScrollContainer: React.RefObject; + refGrid: React.RefObject; + + constructor(props: DraggableGridProps) { + super(props); + this.refScrollContainer = React.createRef(); + this.refGrid = React.createRef(); + + this.state = { + indexToSelect: props.defaultSelectedIndex + }; + + this.handlePointerDownCapture = this.handlePointerDownCapture.bind(this); + this.handlePointerDown = this.handlePointerDown.bind(this); + this.handlePointerCancel = this.handlePointerCancel.bind(this); + this.handlePointerMove = this.handlePointerMove.bind(this); + this.handlePointerUp = this.handlePointerUp.bind(this); + this.onClick = this.onClick.bind(this); + this.handleAutoScrollTick = this.handleAutoScrollTick.bind(this); + this.animationTick = this.animationTick.bind(this); + this.longPressTimerTick = this.longPressTimerTick.bind(this); + this.handleTouchMove = this.handleTouchMove.bind(this); + this.handleTouchEnd = this.handleTouchEnd.bind(this); + } + + animationData: AnimationData[] = []; + + + handleTouchMove(e: any) + { + if (this.dragStarted) + { + e.preventDefault(); + } + } + handleTouchEnd(e: any) + { + if (this.dragStarted) + { + e.preventDefault(); + } + + } + + animationStartTime: number = 0; + timerHandle: number| null = null; + + animationTick() { + let t = (new Date().getTime() - this.animationStartTime) / ANIMATION_DURATION_MS; + if (t > 1) t = 1; + + // easing function. + //t = 1-(1-t)*(1-t); + let didAnimate: boolean = false; + for (let i = 0; i < this.animationData.length; ++i) { + let animationData = this.animationData[i]; + if (animationData.animating) + { + if (i !== this.startIndex) { + //if ((animationData.xFrom !== animationData.xTo) || (animationData.yFrom !== animationData.yTo)) + let y = t * (animationData.toY - animationData.fromY) + animationData.fromY; + let style = animationData.element.style; + style.left = "0px"; + style.top = y-animationData.originalPosition.y + "px"; + animationData.currentY = y; + animationData.animating = animationData.toY !== animationData.fromY; + if (animationData.animating) didAnimate = true; + } + } + } + if (t < 1 && didAnimate) { + this.timerHandle = requestAnimationFrame(this.animationTick) + } else { + this.timerHandle = null; + } + + } + startAnimation() { + this.animationStartTime = new Date().getTime(); + + if (this.timerHandle === null) { + + this.timerHandle = requestAnimationFrame(this.animationTick); + this.animationTick(); + } + } + stopAnimation() { + if (this.timerHandle !== null) { + cancelAnimationFrame(this.timerHandle); + } + this.timerHandle = null; + } + + isValidPointer(e: PointerEvent): boolean + { + if (e.pointerType === "mouse") { + return e.button === 0; + } else if (e.pointerType === "pen") { + return true; + } else if (e.pointerType === "touch") { + return true; + } + return false; + } + + bringSelectedItemIntoView() { + if (this.state.indexToSelect && this.state.indexToSelect >= 0) + { + let grid = this.refGrid.current; + if (grid) + { + if (this.state.indexToSelect >= 0 && this.state.indexToSelect < grid.childNodes.length) + { + let element = grid.childNodes[this.state.indexToSelect] as HTMLElement; + element.scrollIntoView({ + block: "nearest", + inline: "nearest" + }); + } + } + } + } + componentDidMount() { + this.bringSelectedItemIntoView(); + // this.refGrid.current!.addEventListener("touchstart",(e)=> this.handleTouchStart(e),{passive: false}); + } + componentWillUnmount() + { + //this.refGrid.current!.removeEventListener("touchstart",(e) => this.handleTouchStart(e)); + this.stopAnimation(); + + } + + componentDidUpdate() { + if (!this.mouseDown) + { + this.bringSelectedItemIntoView(); + } + if (this.mouseDown) + { + this.reprepareChildren(); + this.reflowChildren(); + this.stopAnimation(); + this.animationTick(); + } + } + + mouseDown: boolean = false; + pointerId: number = 0; + pointerType: string = ""; + + lastOnDragTime: number = 0; + + onClick(e: MouseEvent) { + // if the click event immediately follows drag end, suppress it. + let dt = new Date().getTime() - this.lastOnDragTime; + if (dt < 150) { + e.preventDefault(); + e.stopPropagation(); + } + + } + hasClass(element: HTMLElement, className: string) { + let classes = element.classList; + for (let i = 0; i < classes.length; ++i) { + if (classes[i] === className) return true; + } + return false; + } + findGridItem(element: any | null): HTMLDivElement | null { + let grid = this.refGrid.current; + if(!grid) return null; + while (element !== null && element !== grid) { + if (element.parentElement === grid) { + return element as HTMLDivElement; + } + element = element.parentElement; + } + return null; + } + isCapturedPointer(e: PointerEvent): boolean { + return this.mouseDown + && e.pointerId === this.pointerId + && e.pointerType === this.pointerType; + + } + + startX: number = 0; + startY: number = 0; + startClientX: number = 0; + startClientY: number = 0; + dragStarted: boolean = false; + savedIndex: string = ""; + savedBackground: string = ""; + lastPointerDown: number = 0; + + ptItemStart: DOMPoint = new DOMPoint(0, 0); + captureElement?: HTMLDivElement; + + handlePointerDownCapture(e: any) { + // a new pointer down of any type cancels capture + this.cancelDrag(); + e.preventDefault(); + e.stopPropagation(); + } + + + + cancelDrag() { + //window.removeEventListener("touchstart",this.handleTouchStart); + window.removeEventListener("touchmove",this.handleTouchMove); + window.removeEventListener("touchend",this.handleTouchEnd); + + if (this.originalOverscrollBehaviourY) + { + this.getScrollContainer()!.style.setProperty("overscroll-behaviour-y",this.originalOverscrollBehaviourY); + this.originalOverscrollBehaviourY = undefined; + } + + if (this.longPressTimer) { + clearTimeout(this.longPressTimer); + this.longPressTimer = undefined; + } + this.stopAnimation(); + this.stopAutoScroll(); + if (this.dragStarted && this.captureElement) { + try { + this.captureElement.releasePointerCapture(this.pointerId); + } catch (error) + { + // throws if we've already lost it. + } + + } + this.dragStarted = false; + if (this.dragTarget) { + this.clearDragTransform(this.dragTarget); + this.dragTarget = null; + } + this.captureElement = undefined; + this.mouseDown = false; + this.unprepareChildren(); + + document.body.removeEventListener("pointerdown", this.handlePointerDownCapture, true); + } + + + prepareChildren() { + if (this.refGrid.current === null) return; + let grid = this.refGrid.current; + let nodes = grid.childNodes; + let childRects = []; + + let gridClientRect = grid.getBoundingClientRect(); + for (let i = 0; i < nodes.length; ++i) { + let child = nodes[i] as HTMLDivElement; + let rect = child.getBoundingClientRect(); + rect.x -= gridClientRect.left; + rect.y -= gridClientRect.top; + childRects[i] = rect; + } + for (let i = 0; i < nodes.length; ++i) { + let child = nodes[i] as HTMLDivElement; + child.style.position = "relative"; + child.style.left = "0px"; + child.style.top = "0px"; + } + this.animationData = []; + for (let i = 0; i < nodes.length; ++i) { + this.animationData[i] = new AnimationData(nodes[i] as HTMLElement, childRects[i]); + } + grid.style.height = this.gridBounds.height + "px"; + grid.style.width = this.gridBounds.width + "px"; + + } + reprepareChildren() + { + if (this.refGrid.current === null) return; + let grid = this.refGrid.current; + let nodes = grid.childNodes; + + for (let i = 0; i < nodes.length; ++i) { + let child = nodes[i] as HTMLDivElement; + child.style.position = "relative"; + child.style.left = "0px"; + child.style.top = "0px"; + } + if (nodes.length !== this.animationData.length) + { + this.cancelDrag(); + return; + } + for (let i = 0; i < nodes.length; ++i) { + let key: any = (nodes[i] as any).key; + if (nodes[i] as HTMLElement !== this.animationData[i].element) { + console.log("Animation failed: Element " + i + " changed."); + } + if (key !== this.animationData[i].key) { + console.log("Animation failed: Element " + i + " key has changed."); + } + this.animationData[i].element = nodes[i] as HTMLElement; + if (i !== this.startIndex) + { + this.animationData[i].animating = true; + } + } + grid.style.height = this.gridBounds.height + "px"; + grid.style.width = this.gridBounds.width + "px"; + this.animationTick(); + + + } + + getIndexFromPosition(clientX: number, clientY: number) + { + let grid = nullCast(this.refGrid.current); + let gridBounds = grid.getBoundingClientRect(); + clientX -= gridBounds.left; + clientY -= gridBounds.top; + + if (clientY < 0) return -1; + for (let i = 0; i < this.animationData.length; ++i) + { + let item = this.animationData[i]; + if (clientY >= item.originalPosition.x && clientY < item.originalPosition.bottom) + { + return i; + } + } + return -1; + + + } + getDragIndexFromPosition(clientX: number, clientY: number): number { + + let grid = nullCast(this.refGrid.current); + + let originalBounds = this.animationData[this.startIndex].originalPosition; + // Base test on the CENTER point of the currently dragged item. + clientX += originalBounds.width / 2 - this.ptItemStart.x; + clientY += originalBounds.height / 2 - this.ptItemStart.y; + + let gridBounds = grid.getBoundingClientRect(); + + clientX -= gridBounds.x; + clientY -= gridBounds.top; + + // clientX/Y is now the position of the center of the currently-dragged item, in the coordinates of the contenst of the scroll view (scroll applied) + + + if (clientY < 0) return 0; + for (let i = 0; i < this.animationData.length; ++i) { + let rect = this.animationData[i].originalPosition; + + if (clientY >= rect.top && clientY < rect.bottom) + { + return i; + } + } + return this.animationData.length-1; + } + + + unprepareChildren() { + if (this.refGrid.current === null) return; + let grid = this.refGrid.current; + let nodes = grid.childNodes; + + for (let i = 0; i < nodes.length; ++i) { + let child = nodes[i] as HTMLDivElement; + child.style.position = ""; + child.style.top = "" + child.style.left = ""; + child.style.width = ""; + child.style.height = ""; + } + + grid.style.height = ""; + grid.style.width = "100%"; + + // releast refs and storage. + this.dragTarget = null; + this.animationData = []; + + } + + dragTarget: HTMLDivElement | null = null; + + elementKeys: any[] = []; + + + + clearDragTransform(element: HTMLDivElement): void { + element.style.transform = ""; + element.style.zIndex = this.savedIndex; + element.style.background = this.savedBackground; + element.style.opacity = "1"; + + } + + handlePointerCancel(e: PointerEvent) { + if (this.isCapturedPointer(e)) { + this.cancelDrag(); + if (this.props.onDragCancel) { + this.props.onDragCancel(e.clientX, e.clientY); + } + } + } + + handlePointerUp(e: PointerEvent) { + if (this.isCapturedPointer(e)) { + + this.assertKeysNotChanged(this.elementKeys); // make sure that a late render hasn't swapped elements while we're dragging. + + this.handlePointerMove(e); + e.preventDefault(); + e.stopPropagation(); + if (this.dragStarted) { + this.lastOnDragTime = new Date().getTime(); + if (this.props.onDragEnd) { + this.props.onDragEnd( + this.startIndex, this.currentIndex, + e.clientX, e.clientY); + } + if (this.startIndex !== this.currentIndex) { + this.props.moveElement(this.startIndex, this.currentIndex); + } + } + this.cancelDrag(); + } + } + + dragThresholdExceeded(e: PointerEvent) { + if (this.pointerType === "touch") + { + let timeMs = new Date().getTime(); + let dt = timeMs -this.lastPointerDown; + if (dt < LONG_PRESS_TIME_MS) return false; + } + + let dx = e.clientX - this.startX; + let dy = e.clientY - this.startY; + let d2 = dx * dx + dy * dy; + + let DRAG_THRESHOLD = 5; + if (this.pointerType === "touch") + { + DRAG_THRESHOLD = 15; + } + return (d2 > DRAG_THRESHOLD * DRAG_THRESHOLD); + } + + lastX: number = 0; + lastY: number = 0; + + translateViewPortPoint(fromElement: HTMLElement, toElement: HTMLElement, pt: Point): Point { + let rcFrom = fromElement.getBoundingClientRect(); + let rcTo = toElement.getBoundingClientRect(); + + return { + x: pt.x + rcFrom.left + fromElement.scrollLeft - rcTo.left - toElement.scrollLeft, + y: pt.y + rcFrom.top + fromElement.scrollTop - rcTo.top - toElement.scrollTop + + }; + } + + makeTransform(targetElement: HTMLElement, clientX: number, clientY: number): string { + + // the bounds of the translated element must COMPLETELY fit within the scroll range of the container. + let originalBounds = this.animationData[this.startIndex].originalPosition; + + let newLocation = new DOMRect( + originalBounds.x + clientX - this.startX, + originalBounds.y + clientY - this.startY, + originalBounds.width, + originalBounds.height); + + + if (newLocation.x < 0) { + newLocation.x = 0; + } else if (newLocation.right >= this.gridBounds.width) { + newLocation.x -= newLocation.right - this.gridBounds.width; + } + + // chrome: inconsistent scroll height calculations. + let maxY = this.gridBounds.height; + if (newLocation.top < 0) { + newLocation.y = 0; + } else if (newLocation.bottom > maxY) { + newLocation.y -= newLocation.bottom - maxY; + } + + return "translate(" + (newLocation.x - originalBounds.x) + "px," + + (newLocation.y - originalBounds.y) + "px) scale(" + SELECT_SCALE + ")"; + } + + createOriginalBounds(): DOMRect { + // bounds of the target element, in ScrollContainer coordinates. + let rcTarget = nullCast(this.dragTarget).getBoundingClientRect(); + + let rcScroll = nullCast(this.getScrollContainer()).getBoundingClientRect(); + rcTarget.x -= rcScroll.x; + rcTarget.y -= rcScroll.y; + return rcTarget; + } + + startIndex: number = 0; + currentIndex: number = 0; + + + reflowChildren(): void { + + let y = 0; + for (let i = 0; i < this.animationData.length; ++i) { + if (i === this.startIndex) { + if (i === this.currentIndex) { + y += this.animationData[this.startIndex].originalPosition.height; + } + + } else { + if (i === this.currentIndex && this.currentIndex < this.startIndex) + { + y += this.animationData[this.startIndex].originalPosition.height; + } + let animationItem = this.animationData[i]; + animationItem.setPosition(y); + y += animationItem.originalPosition.height; + if (i === this.currentIndex && this.currentIndex > this.startIndex) + { + y += this.animationData[this.startIndex].originalPosition.height; + } + } + } + this.stopAnimation(); + this.animationStartTime = new Date().getTime(); + this.animationTick(); + } + + itemOffsetX: number = 0; + itemOffsetY: number = 0; + longPressTimer?: NodeJS.Timeout = undefined; + + + longPressTimerTick() { + if (navigator.vibrate) + { + navigator.vibrate([5]); + } + if (!this.dragStarted) + { + this.startDrag(); + } + } + + + handlePointerDown(e: PointerEvent): void { + + if (this.props.canDrag !== undefined && !this.props.canDrag) return; + + // any new pointer down cancels a drag in progress. + this.cancelDrag(); + + // avoid 2nd click of a double click (which is difficult to cancel) + let timeMs = new Date().getTime(); + if (timeMs - this.lastPointerDown < 300) { + this.lastPointerDown = timeMs; + return; + } + this.lastPointerDown = timeMs; + + + let gridElement = this.findGridItem(e.target); + if (gridElement === null) return; + + + + if (!this.mouseDown && this.isValidPointer(e)) { + + this.dragTarget = gridElement; + + + document.body.addEventListener("pointerdown", this.handlePointerDownCapture, true); + this.captureElement = e.currentTarget; + + this.elementKeys = this.getElementKeys(); + this.longPressTimer = setTimeout(this.longPressTimerTick,LONG_PRESS_TIME_MS); + this.mouseDown = true; + + ///window.addEventListener("touchstart",this.handleTouchStart, {passive: false}); + + this.dragStarted = false; + this.startX = e.clientX; + this.startY = e.clientY; + this.startClientX = e.clientX; + this.startClientY = e.clientY; + + this.pointerId = e.pointerId; + this.pointerType = e.pointerType; + + this.savedIndex = gridElement.style.zIndex; + gridElement.style.zIndex = "3"; + this.savedBackground = gridElement.style.background; + gridElement.style.background = "#EEE"; + gridElement.style.opacity = "0.8"; + } + } + + originalOverscrollBehaviourY?: string; + + gridBounds: DOMRect = new DOMRect(); + + startDrag() { + this.dragStarted = true; + let grid = this.refGrid.current!; + this.gridBounds = grid.getBoundingClientRect(); + + window.addEventListener("touchmove",this.handleTouchMove, {passive: false}); + window.addEventListener("touchend",this.handleTouchEnd, {passive: false}); + + this.prepareChildren(); + + this.startIndex = this.getIndexFromPosition(this.startX, this.startY); + if (this.startIndex === -1) + { + this.cancelDrag(); + return; + } + let t = grid.childNodes[this.startIndex]; + if (t !== this.dragTarget) { + console.count("dragTarget mismatch!"); + this.startIndex = this.getIndexFromPosition(this.startX,this.startY); + this.dragTarget = grid.childNodes[this.startIndex] as HTMLDivElement; + } + this.currentIndex = this.startIndex; + if (this.props.onDragStart) { + this.props.onDragStart(this.startIndex, this.startX, this.startY); + } + this.dragTarget!.setPointerCapture(this.pointerId); + + let rcItem = this.dragTarget!.getBoundingClientRect(); + this.ptItemStart = new DOMPoint(this.startX - rcItem.x, this.startY - rcItem.y); + + this.originalOverscrollBehaviourY = this.getScrollContainer()!.style.getPropertyValue("overscroll-behaviour-y"); + this.getScrollContainer()!.style.setProperty("overscroll-behaviour-y","none"); + + if (this.pointerType === "touch") + { + this.startY -= 4; // causes the selected item to "pop" + } + } + + handlePointerMove(e: PointerEvent): void { + if (this.isCapturedPointer(e)) { + if (!this.dragStarted && this.dragThresholdExceeded(e)) { + this.startDrag(); + } + if (this.dragStarted) { + this.lastX = e.clientX; + this.lastY = e.clientY; + if (this.dragTarget !== null) { + this.dragTarget.style.transform = this.makeTransform(this.dragTarget, e.clientX, e.clientY); + + let index = this.getDragIndexFromPosition(e.clientX, e.clientY); + if (index !== this.currentIndex) { + this.currentIndex = index; + this.reflowChildren(); + } + } + e.stopPropagation(); + e.preventDefault(); + + if (this.props.onDragMove) { + this.props.onDragMove(this.currentIndex, e.clientX, e.clientY); + } + + this.checkForAutoScroll(e.currentTarget); + } + } + } + autoScrollTimer?: NodeJS.Timeout; + + + getElementKeys(): any[] { + let grid = nullCast(this.refGrid.current); + let children = grid.childNodes; + let result: any[] = []; + for (let i = 0; i < children.length; ++i) + { + result[i] = (children[i] as any).key; + } + return result; + } + + assertKeysNotChanged(oldKeys: any[]) + { + let newKeys = this.getElementKeys(); + for (let i = 0; i < newKeys.length; ++i) + { + if (newKeys[i] !== oldKeys[i]) + { + throw new Error("Keys have changed."); + } + } + } + + handleAutoScrollTick(currentTarget: HTMLElement, dx: number, dy: number) { + if (!this.mouseDown) return; + let scrollContainer = this.getScrollContainer(); + if (scrollContainer) { + let tx = scrollContainer.scrollLeft; + let ty = scrollContainer.scrollTop; + + let x = scrollContainer.scrollLeft + dx; + let y = scrollContainer.scrollTop + dy; + x = Math.min(x,scrollContainer.scrollWidth-scrollContainer.clientWidth); + y = Math.min(y,scrollContainer.scrollHeight-scrollContainer.clientHeight); + if (x < 0) x = 0; + if (y < 0) y = 0; + + scrollContainer.scrollTo(x, y); + this.startX -= (scrollContainer.scrollLeft - tx); + this.startY -= (scrollContainer.scrollTop - ty); + + if (this.dragTarget) { + this.dragTarget.style.transform = this.makeTransform(this.dragTarget, this.lastX, this.lastY); + } + + this.checkForAutoScroll(currentTarget); + } + } + stopAutoScroll() { + if (this.autoScrollTimer !== undefined) { + clearTimeout(this.autoScrollTimer); + this.autoScrollTimer = undefined; + } + } + startAutoScroll(scrollContainer: HTMLElement, dx: number, dy: number) { + this.stopAutoScroll(); + + this.autoScrollTimer = setTimeout( + () => { this.handleAutoScrollTick(scrollContainer, dx, dy) }, AUTOSCROLL_TICK_DELAY); + } + + checkForAutoScroll(currentTarget: HTMLElement) { + let scrollContainer = this.getScrollContainer(); + if (!scrollContainer) { + this.stopAutoScroll(); + return; + } + + + let scrollContainerRect = scrollContainer.getBoundingClientRect(); + + let dy: number = 0; + let dx: number = 0; + + if (this.lastX < scrollContainerRect.x + AUTOSCROLL_THRESHOLD) { + dx = -AUTOSCROLL_SCROLL_RATE; + if (dx < -scrollContainer.scrollLeft) { + dx = -scrollContainer.scrollLeft; + } + } else if (this.lastX >= scrollContainerRect.right - AUTOSCROLL_THRESHOLD) { + dx = AUTOSCROLL_SCROLL_RATE; + let maxScroll = Math.max(scrollContainer.scrollWidth - scrollContainer.clientWidth, 0); + if (dx > maxScroll) dx = maxScroll; + } + if (this.lastY < scrollContainerRect.top) { + dy = -AUTOSCROLL_SCROLL_RATE; + if (dy < -scrollContainer.scrollTop) dy = -scrollContainer.scrollTop; + } else if (this.lastY >= scrollContainerRect.bottom - AUTOSCROLL_THRESHOLD) { + dy = AUTOSCROLL_SCROLL_RATE; + let maxScroll = Math.max(scrollContainer.scrollHeight - scrollContainer.clientHeight); + if (dy > maxScroll) dy = maxScroll; + } + + if (dx === 0 && dy === 0) { + this.stopAutoScroll(); + return; + } else { + this.startAutoScroll(currentTarget, dx, dy); + } + + } + + getScrollContainer(): HTMLDivElement | null { + return this.refScrollContainer.current; + } + + overflowX(): Property.OverflowX { + return this.props.scroll === ScrollDirection.X ? "auto" : "hidden"; + } + overflowY(): Property.OverflowX { + return this.props.scroll === ScrollDirection.Y ? "auto" : "hidden"; + } + + render() { + return ( +
{ e.preventDefault(); e.stopPropagation(); }} + onClick={this.onClick} + ref={this.refScrollContainer} + > +
+ {this.props.children} +
+
+ ) + } + + } + ); + +export default DraggableGrid; diff --git a/react/src/FullScreenIME.tsx b/react/src/FullScreenIME.tsx new file mode 100644 index 0000000..1d2afd9 --- /dev/null +++ b/react/src/FullScreenIME.tsx @@ -0,0 +1,212 @@ +import React, { ReactNode } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import { UiControl } from './Lv2Plugin'; +import Dialog from '@material-ui/core/Dialog'; +import Input from '@material-ui/core/Input'; +import { nullCast } from './Utility'; +import Typography from '@material-ui/core/Typography'; + + +const styles = (theme: Theme) => createStyles({ + frame: { + display: "block", + position: "relative", + flexDirection: "row", + flexWrap: "nowrap", + paddingTop: "8px", + paddingBottom: "0px", + height: "100%", + overflowX: "auto", + overflowY: "auto" + }, + +}); + +interface FullScreenIMEProps extends WithStyles { + theme: Theme; + uiControl?: UiControl; + caption: string; + value: number; + onChange: (key: string, value: number) => void; + onClose: () => void; + initialHeight: number; +}; +type FullScreenIMEState = { + error: boolean; +}; + +const FullScreenIME = + withStyles(styles, { withTheme: true })( + class extends ResizeResponsiveComponent + { + model: PiPedalModel; + inputRef: React.RefObject; + + constructor(props: FullScreenIMEProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.inputRef = React.createRef(); + + this.state = { + error: false + + } + this.onValueChanged = this.onValueChanged.bind(this); + this.handleClose = this.handleClose.bind(this); + this.onInputChange = this.onInputChange.bind(this); + this.onInputKeyPress = this.onInputKeyPress.bind(this); + this.onInputLostFocus = this.onInputLostFocus.bind(this); + } + + onValueChanged(key: string, value: number): void { + this.props.onChange(key, value); + } + + + onWindowSizeChanged(width: number, height: number): void { + + if (this.props.uiControl) { + // detecting a keyboard IME is painfully difficult. + // we do it by comparing the current window height against the window height + // when the IME was requested. + + // a width change indicates a screen flip. Cancel the fullscreen ime in that case + // because we can't determine the initial window heigth anymore. + if (this.currentWidth === undefined) + { + this.currentWidth = window.innerWidth; + } + if (this.currentWidth !== window.innerWidth) + { + this.validateInput(true); + } + // eslint-disable-next-line no-restricted-globals + if (window.innerHeight >= this.props.initialHeight) { + this.validateInput(true); + } + } + } + + + handleClose(e: {}, reason: string): void { + this.props.onClose(); + } + onInputLostFocus() { + this.validateInput(true); + + } + + inputChanged: boolean = false; + onInputChange() { + + this.inputChanged = true; + this.validateInput(false); + } + + currentValue: number = 0; + + validateInput(commitValue: boolean) { + if (!this.inputRef.current) return; + + let text = this.inputRef.current.value; + let valid = false; + let result: number = this.currentValue; + try { + if (text.length === 0) { + valid = false; + } else { + let v = Number(text); + if (isNaN(v)) { + valid = false; + } else { + valid = true; + result = v; + } + } + } catch (error) { + valid = false; + } + + if (commitValue) { + this.setState({ error: false }); + if (!valid) { + result = this.currentValue; // reset the value! + } + // clamp and quantize. + let uiControl = nullCast(this.uiControl); + + // quantize value. + result = uiControl.clampValue(result); + + this.props.onChange(this.props.uiControl!.symbol, result); + } + } + + onInputKeyPress(e: any): void { + if (e.charCode === 13) { + if (this.inputChanged) { + this.inputChanged = false; + this.validateInput(true); + } + else { + this.props.onClose(); + } + } + } + + uiControl?: UiControl; + + currentWidth?: number; + + render(): ReactNode { + //let classes = this.props.classes; + let control = this.props.uiControl; + if (!control) { + this.currentWidth = undefined; + return (
); + } + this.currentWidth = window.innerWidth; + + this.uiControl = control; + + let value = this.props.value; + + return ( + this.handleClose(e, r)} > +
+ {this.props.caption} + + +
+ +
+ ); + + } + + } + ); + +export default FullScreenIME; + diff --git a/react/src/GxTunerControl.tsx b/react/src/GxTunerControl.tsx new file mode 100644 index 0000000..516ba9e --- /dev/null +++ b/react/src/GxTunerControl.tsx @@ -0,0 +1,338 @@ +import React, {Component} from 'react'; +import { createStyles, Theme, withStyles, WithStyles } from '@material-ui/core/styles'; +import { MonitorPortHandle, PiPedalModel, PiPedalModelFactory } from "./PiPedalModel"; +import SvgPathBuilder from './SvgPathBuilder' + +//const char* model[] = {"12-TET","19-TET","24-TET", "31-TET", "53-TET"}; +// set_adjustment(ui->widget[2]->adj,440.0, 440.0, 427.0, 453.0, 0.1, CL_CONTINUOS); + +const FREQUENCY_PORT_NAME = "FREQ"; + +const DIAL_WIDTH= 220; +const DIAL_HEIGHT = 100; +const NEEDLE_CY = 320; +const CENTS_PER_MARK = 5; +const NEEDLE_OUTER_RADIUS = 0.98; +const TICK_OUTER_RADIUS = 0.96; +const TICK_INNER_RADIUS = 0.85; +const TICK_INNER_ZERO_RADIUS = 0.82; +const DIAL_ANGLE_RADIANS = 20*Math.PI/180; + + +const styles = (theme: Theme) => + createStyles({ + icon: { + width: "24px", + height: "24px", + margin: "0px", + opacity: "0.6" + } + }); + +interface PitchInfo { + valid: boolean; + name: string; + fractionText: string; + fraction: number; + + semitoneCents: number +}; + +const FLAT = "\u{266d}"; +const SHARP = "#"; +const DOUBLE_FLAT = "\uD834\uDD2B"; +const DOUBLE_SHARP = "\uD834\uDD2A"; +const HALF_FLAT = "\uD834\uDD33"; +const HALF_SHARP = "\uD834\uDD32"; + + +const NOTES_12TET: string[] = [ + "C", "C" + SHARP, "D", "E"+FLAT,"E", "F", "F" + SHARP, "G", "A"+FLAT,"A","B"+FLAT,"B" +]; +const NOTES_19TET: string[] = [ + "C", "C" + SHARP, "D"+FLAT, "D", "D" + SHARP,"E"+FLAT,"E", "E" + SHARP, "F", "F" + SHARP, "G"+FLAT,"G","G" + SHARP,"A"+FLAT,"A","A" + SHARP,"B"+FLAT,"B","C"+FLAT +]; +const NOTES_24TET: string[] = [ + "C","C"+HALF_SHARP, "C" + SHARP,"D"+HALF_FLAT, "D", "D"+HALF_SHARP, "E"+FLAT, "E"+HALF_FLAT, "E","E"+HALF_SHARP,"F", "F"+HALF_SHARP, "F" + SHARP, "G"+HALF_FLAT,"G","G"+HALF_SHARP, "A"+FLAT,"A"+HALF_FLAT,"A","A"+HALF_SHARP,"B"+FLAT,"B"+HALF_FLAT,"B","C"+HALF_FLAT +]; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const NOTES_31TET: string[] = [ + "C", "D"+DOUBLE_FLAT, "C" + SHARP,"Db","C"+DOUBLE_SHARP,"D","E"+DOUBLE_FLAT,"D" + SHARP,"Eb","D"+DOUBLE_SHARP,"E",'Fb","E" + SHARP,"F","G"+DOUBLE_FLAT,"F" + SHARP,"Gb""Fx","G","A"+DOUBLE_FLAT,"G"+DOUBLE_SHARP,"A"' +]; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const NOTES_53TET = ["la","laa","lo","law","ta","teh","te","tu","tuh","ti","tih","to","taw","da","do","di","daw","ro","rih","ra","ru","ruh","reh","re ","ri","raw","ma","meh","me","mu","muh","mi","maa","mo","maw","fe","fa","fih","fu","fuh","fi","se","suh","su","sih","sol","si","saw","lo","leh","le","lu","luh"]; + +interface GxTunerControlProps extends WithStyles { + theme: Theme; + instanceId: number; +}; +type GxTunerControlState = { + pitchInfo: PitchInfo + tet: number; + refFrequency: number; +}; + +const GxTunerControl = + withStyles(styles, { withTheme: true })( + class extends Component + { + model: PiPedalModel; + + + refRoot: React.RefObject; + + constructor(props: GxTunerControlProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.refRoot = React.createRef(); + + this.state = { + pitchInfo: { + valid: false, + name: "", + fractionText: "", + fraction: 0, + semitoneCents: 100}, + tet: 12, + refFrequency: 440 + + }; + this.onFrequencyUpdated = this.onFrequencyUpdated.bind(this); + } + + + noteToPitchInfo(hz: number) : PitchInfo + { + if (hz < 65) // ground hum. Ignore it. + { + hz = 0; + } + let tet = this.state.tet; + let refFrequency = this.state.refFrequency; + let aOffset: number; + let names: string[]; + let semitoneCents = 100; + let valid = false; + + + switch (tet) + { + case 12: + default: + aOffset = 69; + names = NOTES_12TET; + semitoneCents = 100; + break; + case 19: + aOffset = 4*19+13; + names = NOTES_19TET; + semitoneCents = 100*12.0/19; + break; + case 24: + aOffset = 4*24+18; + semitoneCents = 50; + names = NOTES_24TET; + break; + } + let name = ""; + let fractionText = ""; + let fraction = 0; + if (hz !== 0) + { + + let note = Math.log2(hz/refFrequency)*tet + aOffset; + let noteNumber = Math.round(note); + + let octave = Math.floor((noteNumber)/tet); + + let nameIndex = noteNumber -octave* tet; + if (nameIndex < 0) nameIndex += tet; + name = names[ nameIndex ] + (octave-2); + valid = true; + fraction = note-noteNumber; + if (fraction >= 0) { + fractionText = "+" + fraction.toFixed(2).substr(1); + } else { + fractionText = "\u2212" + fraction.toFixed(2).substr(2); + + } + } + return { + valid: valid, + name: name, + fraction: fraction, + fractionText: fractionText, + semitoneCents: semitoneCents + }; + } + + lastValue: number = -1; + onFrequencyUpdated(value: number): void + { + // suppress repeated zeros. + if (value === this.lastValue && value === 0 && this.animationIdle) return; + + this.lastValue = value; + + let pitchInfo = this.noteToPitchInfo(value); + this.setState({ + pitchInfo: pitchInfo + }); + } + + subscribedInstanceId: number = -1; + + monitorHandle?: MonitorPortHandle; + + addSubscription() { + this.subscribedInstanceId = this.props.instanceId; + this.monitorHandle = this.model.monitorPort(this.props.instanceId,FREQUENCY_PORT_NAME,1.0/30,this.onFrequencyUpdated); + } + removeSubscription() { + this.subscribedInstanceId = -1; + if (this.monitorHandle) { + this.model.unmonitorPort(this.monitorHandle); + this.monitorHandle = undefined; + } + } + updateSubscription() { + if (this.subscribedInstanceId !== this.props.instanceId) + { + this.removeSubscription(); + this.addSubscription(); + + } + } + componentDidMount() + { + this.addSubscription(); + } + componentDidUpdate() { + this.updateSubscription(); + } + componentWillUnmount() + { + this.removeSubscription(); + } + + + + makeDialTick(pitchInfo: PitchInfo, cents: number): React.ReactNode { + let isZeroTick = Math.abs(cents) < 0.001; + let r0 = TICK_OUTER_RADIUS; + let r1 = (isZeroTick? TICK_INNER_ZERO_RADIUS: TICK_INNER_RADIUS); + let width = isZeroTick? 3: 2; + return this.makeTick(pitchInfo,cents,r0,r1,"#666", width); + } + + makeTick(pitchInfo: PitchInfo, cents: number, r0: number, r1: number, stroke: string,width: number): React.ReactNode + { + let range = pitchInfo.semitoneCents; + if (range > 50) { + range = 50; + } + r0 *= NEEDLE_CY; + r1 *= NEEDLE_CY; + let angle = DIAL_ANGLE_RADIANS * (cents*2/(range)); + + let sin_ = Math.sin(angle); + let cos_ = -Math.cos(angle); + let cx = DIAL_WIDTH/2; + let cy = NEEDLE_CY; + let path = new SvgPathBuilder().moveTo(r0*sin_+cx,r0*cos_+cy).lineTo(r1*sin_+cx,r1*cos_+cy).toString(); + + return (); + } + + lastValidTime: number = 0; + lastValidCents: number = -100; + animationIdle: boolean = true; + + makeNeedle(pitchInfo: PitchInfo) + { + let maxCents = pitchInfo.semitoneCents/2; + if (maxCents > 25) { + maxCents = 25; + } + let cents: number; + if (!pitchInfo.valid) + { + const NEEDLE_DECAY_RATE_PER_MS = -25/100; + + // animate to zero position. + let time = new Date().getTime(); + let dt = time-this.lastValidTime; + + cents = this.lastValidCents+(dt*NEEDLE_DECAY_RATE_PER_MS); + if (cents <= -maxCents) + { + cents = -maxCents; + this.animationIdle = true; + } else { + this.animationIdle = false; + } + } else { + cents = pitchInfo.semitoneCents*pitchInfo.fraction; + if (cents > maxCents) { + cents = maxCents; + } + if (cents < -maxCents) + { + cents = -maxCents; + } + this.lastValidCents = cents; + this.lastValidTime = new Date().getTime(); + } + return this.makeTick(pitchInfo,cents,NEEDLE_OUTER_RADIUS,0.1,"#800",3); + } + + renderDial(pitchInfo: PitchInfo) + { + + let bounds = "0,0," + DIAL_WIDTH+ "," +DIAL_HEIGHT; + + let content: React.ReactNode[] = []; + + let maxCents = Math.floor(pitchInfo.semitoneCents/2 / CENTS_PER_MARK)*CENTS_PER_MARK; + + for (let cents = -maxCents; cents <= maxCents+ 0.01; cents += CENTS_PER_MARK) { + content.push(this.makeDialTick(pitchInfo,cents)); + } + + content.push( + this.makeNeedle(pitchInfo) + ); + + + return ( + + { content } + + ) + } + + render() { + + return (
+
+ {this.state.pitchInfo.name} +
+
+ {this.state.pitchInfo.fractionText} +
+ + { this.renderDial(this.state.pitchInfo) } +
); + } + } + ); + + + + +export default GxTunerControl; \ No newline at end of file diff --git a/react/src/IControlViewFactory.tsx b/react/src/IControlViewFactory.tsx new file mode 100644 index 0000000..fbaa75e --- /dev/null +++ b/react/src/IControlViewFactory.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { PiPedalModel } from "./PiPedalModel"; +import { PedalBoardItem } from './PedalBoard'; + + + +interface IControlViewFactory { + uri: string; + Create(model: PiPedalModel,pedalBoardItem: PedalBoardItem): React.ReactNode; + +} + +export default IControlViewFactory; diff --git a/react/src/Jack.tsx b/react/src/Jack.tsx new file mode 100644 index 0000000..b095701 --- /dev/null +++ b/react/src/Jack.tsx @@ -0,0 +1,100 @@ +import {PiPedalArgumentError} from './PiPedalError'; + +export class JackChannelSelection { + deserialize(input: any): JackChannelSelection + { + this.inputAudioPorts = input.inputAudioPorts.slice(); + this.outputAudioPorts = input.outputAudioPorts.slice(); + this.inputMidiPorts = input.inputMidiPorts.slice(); + this.sampleRate = input.sampleRate; + this.bufferSize = input.bufferSize; + this.numberOfBuffers = input.numberOfBuffers; + return this; + } + clone() : JackChannelSelection { + return new JackChannelSelection().deserialize(this); + } + inputAudioPorts: string[] = []; + outputAudioPorts: string[] = []; + inputMidiPorts: string[] = []; + + sampleRate: number = 48000; + bufferSize: number = 64; + numberOfBuffers: number = 3; + + static makeDefault(jackConfiguration: JackConfiguration): JackChannelSelection { + let result = new JackChannelSelection(); + result.inputAudioPorts = jackConfiguration.inputAudioPorts.slice(0,2); + result.outputAudioPorts = jackConfiguration.inputAudioPorts.slice(0,2); + return result; + } + getChannelDisplayValue(selectedChannels: string[], availableChannels: string[],isConfigValid: boolean): string + { + if (!isConfigValid) + { + if (selectedChannels.length === 2) { + return "Stereo"; + } + if (selectedChannels.length === 1) return "Mono"; + return "Invalid selection"; + + } + if (selectedChannels.length === 0) return "Invalid selection"; + if (availableChannels.length === 1) return "Mono"; + if (availableChannels.length === 2) { + if (selectedChannels.length === 2) return "Stereo"; + if (selectedChannels[0] === availableChannels[0]) { + return "Mono (left channel only)"; + } else if (selectedChannels[0] === availableChannels[1]) { + return "Mono (right channel only)"; + } else { + throw new PiPedalArgumentError("Invalid channel selection."); // should be subset of jackConfiguration. + } + } else { + if (selectedChannels.length === 2) return "Stereo (custom selection)"; + if (selectedChannels.length === 1) return "Mono (custom selection)"; + throw new PiPedalArgumentError("Invalid channel selection."); // should be subset of jackConfiguration. + } + } + getAudioInputDisplayValue(jackConfiguration: JackConfiguration): string + { + return this.getChannelDisplayValue(this.inputAudioPorts,jackConfiguration.inputAudioPorts, jackConfiguration.isValid); + } + getAudioOutputDisplayValue(jackConfiguration: JackConfiguration): string + { + return this.getChannelDisplayValue(this.outputAudioPorts,jackConfiguration.outputAudioPorts, jackConfiguration.isValid); + } + +}; + +export class JackConfiguration { + deserialize(input: any): JackConfiguration { + this.isValid = input.isValid; + this.isRestarting = input.isRestarting; + this.errorState = input.errorState; + this.sampleRate = input.sampleRate; + this.blockLength = input.blockLength; + this.midiBufferSize = input.midiBufferSize; + this.maxAllowedMidiDelta = input.maxAllowedMidiDelta; + this.inputAudioPorts = input.inputAudioPorts; + this.outputAudioPorts = input.outputAudioPorts; + this.inputMidiPorts = input.inputMidiPorts; + this.outputMidiPorts = input.outputMidiPorts; + return this; + } + isValid: boolean = false; + isRestarting: boolean = false; + errorState: string = "Not loaded."; + sampleRate: number = 0; + blockLength: number = 0; + midiBufferSize: number = 0; + maxAllowedMidiDelta: number = 0; + + inputAudioPorts: string[] = []; + outputAudioPorts: string[] = []; + inputMidiPorts: string[] = []; + outputMidiPorts: string[] = []; + +}; + +export default JackConfiguration; \ No newline at end of file diff --git a/react/src/JackHostStatus.tsx b/react/src/JackHostStatus.tsx new file mode 100644 index 0000000..966edeb --- /dev/null +++ b/react/src/JackHostStatus.tsx @@ -0,0 +1,112 @@ +import React from 'react'; +import Typography from '@material-ui/core/Typography'; + + +const RED_COLOR = "#C00"; +const GREEN_COLOR = "#666"; + + + +function tempDisplay(mC: number): string +{ + return (mC/1000).toFixed(1) + "\u00B0C"; // degrees C. +} +function cpuDisplay(cpu: number): string +{ + return cpu.toFixed(1)+"%"; +} + +export default class JackHostStatus { + deserialize(input: any): JackHostStatus + { + this.active = input.active; + this.restarting = input.restarting; + this.underruns = input.underruns; + this.cpuUsage = input.cpuUsage; + this.msSinceLastUnderrun = input.msSinceLastUnderrun; + this.temperaturemC = input.temperaturemC; + return this; + } + hasTemperature() : boolean { + return this.temperaturemC >= -100000; + } + active: boolean = false; + restarting: boolean = false; + underruns: number = 0; + cpuUsage: number = 0; + msSinceLastUnderrun: number = -5000*1000; + temperaturemC: number = -1000000; + + static getDisplayView(label: string,status?: JackHostStatus): React.ReactNode { + if (!status) { + return (
+ {label} +   +
); + } + if (status.restarting) + { + return ( +
+ {label} + + Restarting   + + { + status.temperaturemC > -100000 && + ( + 75000? RED_COLOR: GREEN_COLOR}}> + {tempDisplay(status.temperaturemC)} + + ) + } + +
+ ); + + } else if (!status.active) { + return ( +
+ {label} + + + Stopped   + + { + status.temperaturemC > -100000 && + ( + 75000? RED_COLOR: GREEN_COLOR}}> + {tempDisplay(status.temperaturemC)} + + ) + } +
+ ); + } else { + let underrunError = status.msSinceLastUnderrun < 15*1000; + return ( +
+ {label} + + + XRuns: {status.underruns+""}   + + + + + CPU: {cpuDisplay(status.cpuUsage)}   + + + + + {tempDisplay(status.temperaturemC)} + + +
+ ); + + + } + } + +}; \ No newline at end of file diff --git a/react/src/JackServerSettings.tsx b/react/src/JackServerSettings.tsx new file mode 100644 index 0000000..11ab036 --- /dev/null +++ b/react/src/JackServerSettings.tsx @@ -0,0 +1,35 @@ + + +export default class JackServerSettings { + deserialize(input: any) : JackServerSettings{ + this.valid = input.valid; + this.rebootRequired = input.rebootRequired; + this.sampleRate = input.sampleRate; + this.bufferSize = input.bufferSize; + this.numberOfBuffers = input.numberOfBuffers; + return this; + } + constructor(sampleRate?: number, bufferSize?: number, numberOfBuffers?: number) + { + if (sampleRate) this.sampleRate = sampleRate; + if (bufferSize) this.bufferSize = bufferSize; + if (numberOfBuffers) this.numberOfBuffers = numberOfBuffers; + if (numberOfBuffers) { + this.valid = true; + } + } + valid: boolean = false; + rebootRequired = false; + sampleRate = 48000; + bufferSize = 64; + numberOfBuffers = 3; + + getSummaryText() { + if (this.valid) { + return "Sample Rate: " + this.sampleRate + " BufferSize: " + this.bufferSize + " Number of Buffers: " + this.numberOfBuffers; + } else { + return ""; + } + } + +} \ No newline at end of file diff --git a/react/src/JackServerSettingsDialog.tsx b/react/src/JackServerSettingsDialog.tsx new file mode 100644 index 0000000..427937a --- /dev/null +++ b/react/src/JackServerSettingsDialog.tsx @@ -0,0 +1,169 @@ + +import React, { Component } from 'react'; + +import { createStyles, WithStyles, withStyles, Theme } from '@material-ui/core/styles'; + +import Button from '@material-ui/core/Button'; +import DialogActions from '@material-ui/core/DialogActions'; +import Dialog from '@material-ui/core/Dialog'; +import JackServerSettings from './JackServerSettings'; + + +import InputLabel from '@material-ui/core/InputLabel'; +import FormControl from '@material-ui/core/FormControl'; +import Select from '@material-ui/core/Select'; +import DialogContent from '@material-ui/core/DialogContent'; +import MenuItem from '@material-ui/core/MenuItem'; +import { nullCast } from './Utility'; +import Typography from '@material-ui/core/Typography'; + +interface JackServerSettingsDialogState { + latencyText: string; +}; + +const styles = (theme: Theme) => + createStyles({ + formControl: { + margin: theme.spacing(1), + minWidth: 120, + }, + selectEmpty: { + marginTop: theme.spacing(2), + }, + }); +export interface JackServerSettingsDialogProps extends WithStyles { + open: boolean; + jackServerSettings: JackServerSettings; + onClose: () => void; + onApply: (sampleRate: number, bufferSize: number, numberOfBuffers: number) => void; +} + +function getLatencyText(sampleRate: number, bufferSize: number, numberOfBuffers: number): string { + let ms = bufferSize * numberOfBuffers / sampleRate * 1000; + return ms.toFixed(1) + "ms"; +} + +const JackServerSettingsDialog = withStyles(styles)( + class extends Component { + constructor(props: JackServerSettingsDialogProps) { + super(props); + let jackServerSettings = props.jackServerSettings; + + this.state = { + latencyText: + getLatencyText( + jackServerSettings.sampleRate, + jackServerSettings.bufferSize, + jackServerSettings.numberOfBuffers) + }; + } + + updateLatency(e: any): void { + setTimeout(()=> { + let sampleRate: number = parseInt(nullCast(document.getElementById('jsd_sampleRate')).value); + let bufferSize: number = parseInt(nullCast(document.getElementById('jsd_bufferSize')).value); + let bufferCount: number = parseInt(nullCast(document.getElementById('jsd_bufferCount')).value); + this.setState({ + latencyText: getLatencyText(sampleRate, bufferSize, bufferCount) + }); + },0); + } + handleApply() { + let sampleRate = parseInt(nullCast(document.getElementById('jsd_sampleRate')).value); + let bufferSize = parseInt(nullCast(document.getElementById('jsd_bufferSize')).value); + let bufferCount = parseInt(nullCast(document.getElementById('jsd_bufferCount')).value); + + this.props.onApply(sampleRate,bufferSize,bufferCount); + }; + + + render() { + const classes = this.props.classes; + + const { onClose, jackServerSettings, open } = this.props; + + const handleClose = () => { + onClose(); + }; + + return ( + + + + Sample rate + + +
+ + Buffer size + + + + Buffers + + +
+ + Latency: {this.state.latencyText} + +
+ + + + + + +
+ ); + } + }); + +export default JackServerSettingsDialog; diff --git a/react/src/JackStatusView.tsx b/react/src/JackStatusView.tsx new file mode 100644 index 0000000..acff555 --- /dev/null +++ b/react/src/JackStatusView.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { PiPedalModel, PiPedalModelFactory,State } from './PiPedalModel'; +import JackHostStatus from './JackHostStatus'; + + + + +interface JackStatusViewProps { + +}; + +interface JackStatusViewState { + jackStatus?: JackHostStatus; +} + + +export default class JackStatusView extends React.Component +{ + model: PiPedalModel; + + constructor(props: JackStatusViewProps) { + super(props); + this.state = { + jackStatus: undefined + }; + this.model = PiPedalModelFactory.getInstance(); + this.tick = this.tick.bind(this); + } + + tick() { + if (this.model.state.get() === State.Ready) { + this.model.getJackStatus() + .then(jackStatus => { + this.setState({jackStatus: jackStatus}); + }) + .catch(error => { /* ignore*/ }); + } + } + + timerHandle?: NodeJS.Timeout; + componentDidMount() { + this.timerHandle = setInterval(this.tick, 1000); + } + componentWillUnmount() { + if (this.timerHandle) { + clearTimeout(this.timerHandle); + this.timerHandle = undefined; + } + } + + render() { + return ( +
+ {JackHostStatus.getDisplayView("",this.state.jackStatus) } +
+ ); + + } +} \ No newline at end of file diff --git a/react/src/LoadPluginDialog.tsx b/react/src/LoadPluginDialog.tsx new file mode 100644 index 0000000..92d143a --- /dev/null +++ b/react/src/LoadPluginDialog.tsx @@ -0,0 +1,453 @@ +import React, { ReactNode, SyntheticEvent } from 'react'; +import Grid from '@material-ui/core/Grid'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { UiPlugin, PluginType } from './Lv2Plugin'; +import ButtonBase from '@material-ui/core/ButtonBase'; +import Button from '@material-ui/core/Button'; +import MenuItem from '@material-ui/core/MenuItem'; +import Typography from '@material-ui/core/Typography'; +import PluginInfoDialog from './PluginInfoDialog' +import PluginIcon from './PluginIcon' +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import SelectHoverBackground from './SelectHoverBackground'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import IconButton from '@material-ui/core/IconButton'; +import Select from '@material-ui/core/Select'; +import PluginClass from './PluginClass' +import ClearIcon from '@material-ui/icons/Clear'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import { TransitionProps } from '@material-ui/core/transitions/transition'; +import Slide from '@material-ui/core/Slide'; + + +export type CloseEventHandler = () => void; +export type OkEventHandler = (pluginUri: string) => void; + +const NARROW_DISPLAY_THRESHOLD = 600; +const FILTER_STORAGE_KEY = "com.twoplay.piddle.load_dlg.filter"; + + +const pluginGridStyles = (theme: Theme) => createStyles({ + frame: { + + position: "relative", + width: "100%", + height: "100%" + }, + + top: { + top: "0px", + right: "0px", + left: "0px", + bottom: "64px", + position: "relative", + flexGrow: 1, + overflowX: "hidden", + overflowY: "visible" + }, + bottom: { + position: "relative", + bottom: "0px", + height: "64px", + width: "100%", + display: "flex", + flexDirection: "row", + flexWrap: "nowrap", + justifyContent: "space-between", + paddingLeft: "24px", + paddingRight: "48px", + background: theme.palette.background.paper, + }, + paper: { + position: "relative", + overflow: "hidden", + height: "56px", + width: "100%", + background: theme.palette.background.paper + }, + buttonBase: { + + width: "100%", + height: "100%'" + }, + content: { + marginTop: "8px", + marginBottom: "8px", + marginLeft: "12px", + marginRight: "12px", + width: "100%", + overflow: "hidden", + textAlign: "left", + display: "flex", + flexDirection: "row", + justifyContent: "flex-start", + height: 48, + alignItems: "start", + flexWrap: "nowrap" + }, + content2: { + display: "flex", flexDirection: "column", flex: "1 1 auto", width: "100%", + paddingLeft: 16, whiteSpace: "nowrap" + + }, + table: { + borderCollapse: "collapse", + }, + icon: { + width: "24px", + height: "24px", + margin: "0px", + opacity: "0.6" + }, + iconBorder: { + flex: "0 0 auto" + }, + label: { + width: "100%" + }, + label2: { + marginTop: 8, + color: theme.palette.text.secondary + }, + control: { + padding: theme.spacing(1), + }, + tdText: { + padding: "0px" + + } +}) + ; + +interface PluginGridProps extends WithStyles { + onOk: OkEventHandler; + onCancel: CloseEventHandler; + uri?: string; + minimumItemWidth?: number; + theme: Theme; + open: boolean +}; + +type PluginGridState = { + selected_uri?: string, + hover_uri?: string, + filterType: PluginType, + client_width: number, + client_height: number, + minimumItemWidth: number, + +} +const Transition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + + +export const LoadPluginDialog = + withStyles(pluginGridStyles, { withTheme: true })( + class extends ResizeResponsiveComponent + { + model: PiPedalModel; + + constructor(props: PluginGridProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + let filterType_ = PluginType.Plugin; // i.e. "Any". + let persistedFilter = window.localStorage.getItem(FILTER_STORAGE_KEY); + if (persistedFilter) { + filterType_ = persistedFilter as PluginType; + } + + this.state = { + selected_uri: this.props.uri, + hover_uri: "", + filterType: filterType_, + client_width: window.innerWidth, + client_height: window.innerHeight, + minimumItemWidth: props.minimumItemWidth ? props.minimumItemWidth : 220 + }; + + this.updateWindowSize = this.updateWindowSize.bind(this); + this.handleCancel = this.handleCancel.bind(this); + this.handleOk = this.handleOk.bind(this); + } + + updateWindowSize() { + this.setState({ + client_width: window.innerWidth, + client_height: window.innerHeight + }); + } + componentDidMount() { + super.componentDidMount(); + this.updateWindowSize(); + window.addEventListener('resize', this.updateWindowSize); + } + componentWillUnmount() { + super.componentWillUnmount(); + window.removeEventListener('resize', this.updateWindowSize); + } + + onWindowSizeChanged(width: number, height: number): void { + super.onWindowSizeChanged(width, height); + + } + + onFilterChange(e: any) { + let value = e.target.value as PluginType; + + window.localStorage.setItem(FILTER_STORAGE_KEY, value as string); + + this.setState({ filterType: value }); + } + onClearFilter(): void { + let value = PluginType.Plugin; + window.localStorage.setItem(FILTER_STORAGE_KEY, value as string); + + this.setState({ filterType: value }); + } + + selectItem(item: number): void { + let uri: string = ""; + let plugins = this.model.ui_plugins.get(); + if (item >= 0 && item < plugins.length) { + uri = plugins[item].uri; + } + if (uri !== this.state.selected_uri) { + this.setState({ selected_uri: uri }); + } + }; + + + handleCancel(e: SyntheticEvent): void { + e.preventDefault(); + this.cancel(); + } + handleOk(e: SyntheticEvent): void { + e.preventDefault(); + if (this.state.selected_uri) { + this.props.onOk(this.state.selected_uri); + } + } + + onDoubleClick(e: SyntheticEvent, uri: string): void { + this.props.onOk(uri); + } + + + cancel(): void { + this.props.onCancel(); + } + + fireSelected(item?: UiPlugin) { + if (item) { + this.setState({ selected_uri: item.uri }); + } + } + setHoverUri(uri: string) { + this.setState({ hover_uri: uri }); + } + + onClick(e: SyntheticEvent, uri: string): void { + this.setState({ selected_uri: uri }); + } + handleMouseEnter(e: SyntheticEvent, uri: string): void { + this.setHoverUri(uri); + + } + handleMouseLeave(e: SyntheticEvent, uri: string): void { + this.setHoverUri(""); + + } + onInfoClicked(): void { + // let selectedUri = this.state.selected_uri; + } + + stereo_indicator(uiPlugin?: UiPlugin): string { + if (!uiPlugin) return ""; + if (uiPlugin.audio_inputs === 2 || uiPlugin.audio_outputs === 2) { + return " (Stereo)"; + } + return ""; + } + info_string(uiPlugin?: UiPlugin): string { + if (uiPlugin === undefined) return ""; + let result = uiPlugin.name; + if (uiPlugin.author_name !== "") { + result += ", " + uiPlugin.author_name; + } + result += this.stereo_indicator(uiPlugin); + return result; + } + createFilterChildren(result: ReactNode[], classNode: PluginClass, level: number): void { + for (let i = 0; i < classNode.children.length; ++i) { + let child = classNode.children[i]; + let name = "\u00A0".repeat(level * 3 + 1) + child.display_name; + result.push(({name})); + if (child.children.length !== 0) { + this.createFilterChildren(result, child, level + 1); + } + } + } + createFilterOptions(): ReactNode[] { + let classes = this.model.plugin_classes.get(); + let result: ReactNode[] = []; + + result.push(( All)); + this.createFilterChildren(result, classes, 1); + return result; + + } + filterPlugins(plugins: UiPlugin[]): ReactNode[] { + let result: ReactNode[] = []; + let filterType = this.state.filterType; + let classes = this.props.classes; + let rootClass = this.model.plugin_classes.get(); + + for (let i = 0; i < plugins.length; ++i) { + let value = plugins[i]; + if (filterType === PluginType.Plugin || rootClass.is_type_of(filterType, value.plugin_type)) { + result.push( + ( + { this.onDoubleClick(e, value.uri) }} + onClick={(e) => { this.onClick(e, value.uri) }} + onMouseEnter={(e) => { this.handleMouseEnter(e, value.uri) }} + onMouseLeave={(e) => { this.handleMouseLeave(e, value.uri) }} + > + + +
+
+ +
+
+ + {value.name} + + + {value.plugin_display_type} {this.stereo_indicator(value)} + + +
+
+
+
+ ) + ); + + } + } + return result; + } + + + render() { + const { classes } = this.props; + + + let model = this.model; + let plugins = model.ui_plugins.get(); + + let selectedPlugin: UiPlugin | undefined = undefined; + if (this.state.selected_uri) { + let t = this.model.getUiPlugin(this.state.selected_uri); + if (t) selectedPlugin = t; + } + + return ( + + + + +
+ { this.cancel(); }} style={{ flex: "0 0 auto" }} > + + + + + {this.state.client_width > 520 ? "Select Plugin" : ""} + +
+ +
+ { this.onClearFilter(); }}> + + +
+
+ + + + { + this.filterPlugins(plugins) + } + + + + + {(this.state.client_width >= NARROW_DISPLAY_THRESHOLD) ? ( + +
+
+ + + {this.info_string(selectedPlugin)} + +
+
+ + +
+
+
+ ) : ( + +
+ +
+ + {this.info_string(selectedPlugin)} + +
+
+
+
+ + +
+
+ + + )} +
+
+ ); + } + } + ); +export default LoadPluginDialog; + diff --git a/react/src/LoadPluginDialogBackup.tsx b/react/src/LoadPluginDialogBackup.tsx new file mode 100644 index 0000000..388da1e --- /dev/null +++ b/react/src/LoadPluginDialogBackup.tsx @@ -0,0 +1,441 @@ +import React, { ReactNode, SyntheticEvent } from 'react'; +import Grid from '@material-ui/core/Grid'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { UiPlugin, PluginType } from './Lv2Plugin'; +import Paper from '@material-ui/core/Paper'; +import ButtonBase from '@material-ui/core/ButtonBase'; +import Button from '@material-ui/core/Button'; +import MenuItem from '@material-ui/core/MenuItem'; +import Typography from '@material-ui/core/Typography'; +import PluginInfoDialog from './PluginInfoDialog' +import PluginIcon from './PluginIcon' +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import SelectHoverBackground from './SelectHoverBackground'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import IconButton from '@material-ui/core/IconButton'; +import Select from '@material-ui/core/Select'; +import PluginClass from './PluginClass' +import ClearIcon from '@material-ui/icons/Clear'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import { TransitionProps } from '@material-ui/core/transitions/transition'; +import Slide from '@material-ui/core/Slide'; + + +export type CloseEventHandler = () => void; +export type OkEventHandler = (pluginUri: string) => void; + +const NARROW_DISPLAY_THRESHOLD = 600; +const FILTER_STORAGE_KEY = "com.twoplay.piddle.load_dlg.filter"; + +const Transition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + + + +const pluginGridStyles = (theme: Theme) => createStyles({ + frame: { + + position: "relative", + width: "100%", + height: "100%" + }, + + top: { + top: "0px", + right: "0px", + left: "0px", + bottom: "64px", + position: "relative", + flexGrow: 1, + background: "#eee", + overflowX: "hidden", + overflowY: "visible" + }, + bottom: { + position: "relative", + bottom: "0px", + height: "64px", + width: "100%", + display: "flex", + flexDirection: "row", + flexWrap: "nowrap", + justifyContent: "space-between", + paddingLeft: "24px", + paddingRight: "48px", + background: theme.palette.background.paper, + }, + paper: { + position: "relative", + overflow: "hidden", + height: "56px", + width: "100%", + background: theme.palette.background.paper + }, + buttonBase: { + + width: "100%", + height: "100%'" + }, + content: { + marginTop: "8px", + marginBottom: "8px", + marginLeft: "12px", + marginRight: "12px", + width: "100%", + overflow: "hidden" + }, + table: { + borderCollapse: "collapse", + }, + icon: { + width: "24px", + height: "24px", + margin: "0px", + opacity: "0.6" + }, + label: { + marginLeft: "8px", + + }, + control: { + padding: theme.spacing(1), + }, + tdText: { + padding: "0px" + + } +}) + ; + +interface PluginGridProps extends WithStyles { + onOk: OkEventHandler; + onCancel: CloseEventHandler; + uri?: string; + minimumItemWidth?: number; + theme: Theme; + open: boolean +}; + +type PluginGridState = { + selected_uri?: string, + hover_uri?: string, + filterType: PluginType, + client_width: number, + client_height: number, + minimumItemWidth: number, + +} + + +export const LoadPluginDialog = + withStyles(pluginGridStyles, { withTheme: true })( + class extends ResizeResponsiveComponent + { + model: PiPedalModel; + + constructor(props: PluginGridProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + let filterType_ = PluginType.Plugin; // i.e. "Any". + let persistedFilter = window.localStorage.getItem(FILTER_STORAGE_KEY); + if (persistedFilter) { + filterType_ = persistedFilter as PluginType; + } + + this.state = { + selected_uri: this.props.uri, + hover_uri: "", + filterType: filterType_, + client_width: window.innerWidth, + client_height: window.innerHeight, + minimumItemWidth: props.minimumItemWidth ? props.minimumItemWidth : 220 + }; + + this.updateWindowSize = this.updateWindowSize.bind(this); + this.handleCancel = this.handleCancel.bind(this); + this.handleOk = this.handleOk.bind(this); + } + + updateWindowSize() { + this.setState({ + client_width: window.innerWidth, + client_height: window.innerHeight + }); + } + componentDidMount() { + super.componentDidMount(); + this.updateWindowSize(); + window.addEventListener('resize', this.updateWindowSize); + } + componentWillUnmount() { + super.componentWillUnmount(); + window.removeEventListener('resize', this.updateWindowSize); + } + + onWindowSizeChanged(width: number,height: number): void { + super.onWindowSizeChanged(width,height); + + } + + onFilterChange(e: any) { + let value = e.target.value as PluginType; + + window.localStorage.setItem(FILTER_STORAGE_KEY, value as string); + + this.setState({ filterType: value }); + } + onClearFilter(): void { + let value = PluginType.Plugin; + window.localStorage.setItem(FILTER_STORAGE_KEY, value as string); + + this.setState({ filterType: value }); + } + + selectItem(item: number): void { + let uri: string = ""; + let plugins = this.model.ui_plugins.get(); + if (item >= 0 && item < plugins.length) { + uri = plugins[item].uri; + } + if (uri !== this.state.selected_uri) { + this.setState({ selected_uri: uri }); + } + }; + + + handleCancel(e: SyntheticEvent): void { + e.preventDefault(); + this.cancel(); + } + handleOk(e: SyntheticEvent): void { + e.preventDefault(); + if (this.state.selected_uri) { + this.props.onOk(this.state.selected_uri); + } + } + + onDoubleClick(e: SyntheticEvent, uri: string): void { + this.props.onOk(uri); + } + + + cancel(): void { + this.props.onCancel(); + } + + fireSelected(item?: UiPlugin) { + if (item) { + this.setState({ selected_uri: item.uri }); + } + } + setHoverUri(uri: string) { + this.setState({ hover_uri: uri }); + } + + onClick(e: SyntheticEvent, uri: string): void { + this.setState({ selected_uri: uri }); + } + handleMouseEnter(e: SyntheticEvent, uri: string): void { + this.setHoverUri(uri); + + } + handleMouseLeave(e: SyntheticEvent, uri: string): void { + this.setHoverUri(""); + + } + onInfoClicked(): void { + // let selectedUri = this.state.selected_uri; + } + + stereo_indicator(uiPlugin?: UiPlugin): string { + if (!uiPlugin) return ""; + if (uiPlugin.audio_inputs === 2 || uiPlugin.audio_outputs === 2) { + return " (Stereo)"; + } + return ""; + } + info_string(uiPlugin?: UiPlugin): string { + if (uiPlugin === undefined) return ""; + let result = uiPlugin.name; + if (uiPlugin.author_name !== "") { + result += ", " + uiPlugin.author_name; + } + result += this.stereo_indicator(uiPlugin); + return result; + } + createFilterChildren(result: ReactNode[], classNode: PluginClass, level: number): void { + for (let i = 0; i < classNode.children.length; ++i) { + let child = classNode.children[i]; + let name = "\u00A0".repeat(level * 3+1) + child.display_name; + result.push(({name})); + if (child.children.length !== 0) { + this.createFilterChildren(result, child, level + 1); + } + } + } + createFilterOptions(): ReactNode[] { + let classes = this.model.plugin_classes.get(); + let result: ReactNode[] = []; + + result.push(( All)); + this.createFilterChildren(result, classes, 1); + return result; + + } + filterPlugins(plugins: UiPlugin[]): ReactNode[] { + let result: ReactNode[] = []; + let filterType = this.state.filterType; + let classes = this.props.classes; + let rootClass = this.model.plugin_classes.get(); + + for (let i = 0; i < plugins.length; ++i) { + let value = plugins[i]; + if (filterType === PluginType.Plugin || rootClass.is_type_of(filterType, value.plugin_type)) { + result.push( + ( + { this.onDoubleClick(e, value.uri) }} + onClick={(e) => { this.onClick(e, value.uri) }} + onMouseEnter={(e) => { this.handleMouseEnter(e, value.uri) }} + onMouseLeave={(e) => { this.handleMouseLeave(e, value.uri) }} + > + + + +
+
+
+ +
+
+ {value.name} + + + {value.plugin_display_type} {this.stereo_indicator(value)} + +
+
+
+
+
+
+ ) + ); + + } + } + return result; + } + render() { + const { classes } = this.props; + + + let model = this.model; + let plugins = model.ui_plugins.get(); + + let selectedPlugin: UiPlugin | undefined = undefined; + if (this.state.selected_uri) { + let t = this.model.getUiPlugin(this.state.selected_uri); + if (t) selectedPlugin = t; + } + + return ( + + + + +
+ { this.cancel(); }} style={{ flex: "0 0 auto" }} > + + + + + { this.state.client_width > 520 ? "Select Plugin" : "" } + +
+ +
+ { this.onClearFilter(); }}> + + +
+
+ + + + { + this.filterPlugins(plugins) + } + + + + + { (this.state.client_width >= NARROW_DISPLAY_THRESHOLD)? ( + +
+
+ + + {this.info_string(selectedPlugin)} + +
+
+ + +
+
+
+ ) :( + +
+ +
+ + {this.info_string(selectedPlugin)} + +
+
+
+
+ + +
+
+ + + )} +
+
+ ); + } + } + ); +export default LoadPluginDialog; + diff --git a/react/src/Lv2Plugin.tsx b/react/src/Lv2Plugin.tsx new file mode 100644 index 0000000..0d1d3d1 --- /dev/null +++ b/react/src/Lv2Plugin.tsx @@ -0,0 +1,371 @@ +// Generated by https://quicktype.io +// +// To change quicktype's target language, run command: +// +// "Set quicktype target language" + +import {PiPedalArgumentError} from "./PiPedalError"; +import Units from './Units'; + +interface Deserializable { + deserialize(input: any): T; +} + + +export class Port implements Deserializable { + deserialize(input: any): Port { + this.port_index = input.port_index; + this.symbol = input.symbol; + this.name = input.name; + this.min_value = input.min_value; + this.max_value = input.max_value; + this.default_value = input.default_value; + this.scale_points = ScalePoint.deserialize_array(input.scale_points); + this.is_input = input.is_input; + this.is_output = input.is_output; + this.is_control_port = input.is_control_port; + this.is_audio_port = input.is_audio_port; + this.is_atom_port = input.is_atom_port; + this.is_valid = input.is_valid; + this.supports_midi = input.supports_midi; + this.port_group = input.port_group; + return this; + } + + static EmptyPorts: Port[] = []; + + static deserialize_array(input: any): Port[] { + let result: Port[] = []; + for (let i = 0; i < input.length; ++i) + { + result[i] = new Port().deserialize(input[i]); + } + return result; + } + port_index: number = -1; + symbol: string = ""; + name: string = ""; + min_value: number = 0; + max_value: number = 1; + default_value: number = 0.5; + scale_points: ScalePoint[] = []; + is_input: boolean = false; + is_output: boolean = false + is_control_port: boolean = false; + is_audio_port: boolean = false; + is_atom_port: boolean = false; + is_valid: boolean = false; + supports_midi: boolean = false; + port_group: string = ""; +} + +export class PortGroup { + deserialize(input: any): PortGroup { + this.symbol = input.symbol; + this.name = input.name; + return this; + } + static deserialize_array(input: any) : PortGroup[] { + let result: PortGroup[] = []; + for (let i = 0; i < input.length; ++i) + { + result.push(new PortGroup().deserialize(input[i])); + } + return result; + } + + symbol: string = ""; + name: string = ""; +}; + +export class Lv2Plugin implements Deserializable { + deserialize(input: any): Lv2Plugin + { + this.uri = input.uri; + this.name = input.name; + this.plugin_class = input.plugin_class; + this.supported_features = input.supported_features; + this.required_features = input.required_features; + this.optional_features = input.optional_features; + this.author_name = input.author_name; + this.author_homepage = input.author_homepage; + this.comment = input.comment; + this.ports= Port.deserialize_array(input.ports); + this.port_groups = PortGroup.deserialize_array(input.port_groups); + return this; + } + static EmptyFeatures: string[] = []; + + uri: string = ""; + name: string = ""; + plugin_class: string = ""; + supported_features: string[] = Lv2Plugin.EmptyFeatures; + required_features: string[] = Lv2Plugin.EmptyFeatures; + optional_features: string[] = Lv2Plugin.EmptyFeatures; + author_name: string = ""; + author_homepage: string = ""; + comment: string = ""; + ports: Port[] = Port.EmptyPorts; + port_groups: PortGroup[] = []; +} + + +export class ScalePoint implements Deserializable { + deserialize(input: any): ScalePoint { + this.value = input.value; + this.label = input.label; + return this; + } + static deserialize_array(input: any): ScalePoint[] + { + let result: ScalePoint[] = []; + for (let i = 0; i < input.length; ++i) + { + result[i] = new ScalePoint().deserialize(input[i]); + } + return result; + } + value: number = 0; + label: string = ""; +} + +export enum PluginType { + // Reserved types used in pedalboards. + None="", + InvalidPlugin= "InvalidPlugin", + + Plugin = "Plugin", + AllpassPlugin = "AllpassPlugin", + AmplifierPlugin = "AmplifierPlugin", + AnalyserPlugin = "AnalyserPlugin", + BandpassPlugin = "BandpassPlugin", + ChorusPlugin = "ChorusPlugin", + CombPlugin = "CombPlugin", + CompressorPlugin = "CompressorPlugin", + ConstantPlugin = "ConstantPlugin", + ConverterPlugin = "ConverterPlugin", + DelayPlugin = "DelayPlugin", + DistortionPlugin = "DistortionPlugin", + DynamicsPlugin = "DynamicsPlugin", + EQPlugin = "EQPlugin", + EnvelopePlugin = "EnvelopePlugin", + ExpanderPlugin = "ExpanderPlugin", + FilterPlugin = "FilterPlugin", + FlangerPlugin = "FlangerPlugin", + FunctionPlugin = "FunctionPlugin", + GatePlugin = "GatePlugin", + GeneratorPlugin = "GeneratorPlugin", + HighpassPlugin = "HighpassPlugin", + InstrumentPlugin = "InstrumentPlugin", + LimiterPlugin = "LimiterPlugin", + LowpassPlugin = "LowpassPlugin", + MixerPlugin = "MixerPlugin", + ModulatorPlugin = "ModulatorPlugin", + MultiEQPlugin = "MultiEQPlugin", + OscillatorPlugin = "OscillatorPlugin", + ParaEQPlugin = "ParaEQPlugin", + PhaserPlugin = "PhaserPlugin", + PitchPlugin = "PitchPlugin", + ReverbPlugin = "ReverbPlugin", + SimulatorPlugin = "SimulatorPlugin", + SpatialPlugin = "SpatialPlugin", + SpectralPlugin = "SpectralPlugin", + UtilityPlugin = "UtilityPlugin", + WaveshaperPlugin = "WaveshaperPlugin" +} + + +export class UiControl implements Deserializable { + deserialize(input: any): UiControl + { + this.symbol = input.symbol; + this.name = input.name; + this.index = input.index; + this.min_value = input.min_value; + this.max_value = input.max_value; + this.default_value = input.default_value; + this.is_logarithmic = input.is_logarithmic; + this.display_priority = input.display_priority; + this.range_steps = input.range_steps; + this.integer_property = input.integer_property; + this.enumeration_property = input.enumeration_property; + this.toggled_property = input.toggled_property; + this.trigger = input.trigger; + this.not_on_gui = input.not_on_gui; + this.scale_points = ScalePoint.deserialize_array(input.scale_points); + this.port_group = input.port_group; + this.units = input.units as Units; + return this; + + } + static deserialize_array(input: any): UiControl[] { + let result: UiControl[] = []; + for (let i = 0; i < input.length; ++i) + { + result[i] = new UiControl().deserialize(input[i]); + } + return result; + } + symbol: string = ""; + name: string = ""; + index: number = -1; + min_value: number = 0; + max_value: number = 1; + default_value:number = 0.5; + is_logarithmic: boolean = false; + display_priority: number = -1; + range_steps: number = 0; + integer_property:boolean = false; + enumeration_property: boolean = false; + trigger: boolean = false; + not_on_gui: boolean = false; + toggled_property: boolean = false; + scale_points: ScalePoint[] = []; + port_group: string = ""; + units: Units = Units.none; + + isOnOffSwitch() : boolean { + if (this.isAbToggle()) return false; + if (this.min_value !== 0 || this.max_value !== 1) return false; + return (this.toggled_property || this.enumeration_property || this.integer_property); + ; + } + + isAbToggle(): boolean { + if (this.min_value !== 0 || this.max_value !== 1) return false; + return this.enumeration_property && this.scale_points.length === 2; + } + isSelect() : boolean { + return this.enumeration_property && !this.isOnOffSwitch() && !this.isAbToggle(); + } + + valueToRange(value: number): number { + if (this.toggled_property) return value === 0 ? 0: 1; + + if (this.integer_property || this.enumeration_property) { + value = Math.round(value); + } + let range = (value - this.min_value) / (this.max_value - this.min_value); + if (range > 1) range = 1; + if (range < 0) range = 0; + + if (this.range_steps !== 0) { + range = Math.round(range*this.range_steps)/this.range_steps; + } + + return range; + } + + rangeToValue(range: number) : number { + if (range < 0) range = 0; + if (range > 1) range = 1; + + if (this.toggled_property) return range === 0? 0: 1; + if (this.range_steps !== 0) { + range = Math.round(range * this.range_steps) / this.range_steps; + } + let value = range * (this.max_value - this.min_value) + this.min_value; + if (this.integer_property || this.enumeration_property) { + value = Math.round(value); + } + return value; + } + clampValue(value: number): number { + return this.rangeToValue(this.valueToRange(value)); + } + + formatValue(value: number): string { + if (this.integer_property || this.enumeration_property) { + value = Math.round(value); + } + if (this.enumeration_property) { + for (let i = 0; i < this.scale_points.length; ++i) { + let scale_point = this.scale_points[i]; + if (scale_point.value === value) { + return scale_point.label; + } + } + return "#invalid"; + } else if (this.integer_property) { + return value.toFixed(0); + } else { + if (value >= 100 || value <= -100) { + return value.toFixed(0); + } + if (value >= 10 || value <= -10) { + return value.toFixed(1); + } + return value.toFixed(2); + } + } + + +} + +export class UiPlugin implements Deserializable { + deserialize(input: any): UiPlugin + { + this.uri = input.uri; + this.name = input.name; + this.plugin_type = input.plugin_type as PluginType; + this.plugin_display_type = input.plugin_display_type; + this.author_name = input.author_name; + this.author_homepage = input.author_homepage; + this.audio_inputs = input.audio_inputs; + this.audio_outputs = input.audio_outputs; + this.has_midi_input = input.has_midi_input; + this.has_midi_output = input.has_midi_output; + this.description = input.description; + this.controls = UiControl.deserialize_array(input.controls); + this.port_groups = PortGroup.deserialize_array(input.port_groups); + return this; + + } + static deserialize_array(input: any): UiPlugin[] { + let result: UiPlugin[] = []; + for (let i = 0; i < input.length; ++i) + { + result[i] = new UiPlugin().deserialize(input[i]); + } + return result; + } + getControl(key: string): UiControl | undefined { + for (let i = 0; i < this.controls.length; ++i) + { + let control = this.controls[i]; + if (control.symbol === key) + { + return control; + } + } + return undefined; + + } + getPortGroup(symbol: string): PortGroup + { + for (let i = 0; i < this.port_groups.length; ++i) + { + let port_group = this.port_groups[i]; + if (port_group.symbol === symbol) + { + return port_group; + } + } + throw new PiPedalArgumentError("Port group not found."); + } + + uri: string = ""; + name: string = ""; + plugin_type: PluginType = PluginType.InvalidPlugin; + plugin_display_type: string = ""; + author_name: string = ""; + author_homepage: string = ""; + audio_inputs: number = 0; + audio_outputs: number = 0; + has_midi_input: number = 0; + has_midi_output: number = 0; + description: string = ""; + controls: UiControl[] = []; + port_groups: PortGroup[] = []; +} + diff --git a/react/src/MainPage.tsx b/react/src/MainPage.tsx new file mode 100644 index 0000000..00f1af8 --- /dev/null +++ b/react/src/MainPage.tsx @@ -0,0 +1,452 @@ +import { SyntheticEvent } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { + PedalBoard, PedalBoardItem, PedalBoardSplitItem, SplitType +} from './PedalBoard'; +import Button from '@material-ui/core/Button'; +import InputIcon from '@material-ui/icons/Input'; +import LoadPluginDialog from './LoadPluginDialog'; +import Switch from '@material-ui/core/Switch'; + +import PedalBoardView from './PedalBoardView'; +import { PiPedalStateError } from './PiPedalError'; +import IconButton from '@material-ui/core/IconButton'; +import AddIcon from '@material-ui/icons/Add'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import Fade from '@material-ui/core/Fade'; +import Divider from '@material-ui/core/Divider'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import PluginInfoDialog from './PluginInfoDialog'; +import { GetControlView } from './ControlViewFactory'; +import MidiBindingsDialog from './MidiBindingsDialog'; +import PluginPresetSelector from './PluginPresetSelector'; + + +const SPLIT_CONTROLBAR_THRESHHOLD = 650; + +const HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK = 500; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const HORIZONTAL_LAYOUT_MQ = "@media (max-height: " + HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK + "px)"; + +const styles = ({ palette }: Theme) => createStyles({ + frame: { + position: "absolute", display: "flex", flexDirection: "column", flexWrap: "nowrap", + justifyContent: "flex-start", left: "0px", top: "0px", bottom: "0px", right: "0px", overflow: "hidden" + }, + pedalBoardScroll: { + position: "relative", width: "100%", + flex: "0 0 auto", overflow: "auto", maxHeight: 220 + }, + pedalBoardScrollSmall: { + position: "relative", width: "100%", + flex: "1 1 1px", overflow: "auto" + }, + separator: { + width: "100%", height: "1px", background: "#888", opacity: "0.5", + flex: "0 0 1px" + }, + + controlToolBar: { + flex: "0 0 auto", width: "100%", height: 48 + }, + splitControlBar: { + flex: "0 0 48px", width: "100%", paddingLeft: 24, paddingRight: 16, paddingBottom: 16 + }, + controlContent: { + flex: "1 1 auto", width: "100%", overflowY: "auto", minHeight: 240 + }, + controlContentSmall: { + flex: "0 0 162px", width: "100%", height: 162, overflowY: "hidden", + }, + title: { fontSize: "1.3em", fontWeight: 700, marginRight: 8 }, + author: { fontWeight: 500, marginRight: 8 } +}); + + + +interface MainProps extends WithStyles { + hasTinyToolBar: boolean; + theme: Theme; +}; + +interface MainState { + selectedPedal: number; + loadDialogOpen: boolean; + pedalBoard: PedalBoard; + addMenuAnchorEl: HTMLElement | null; + splitControlBar: boolean; + horizontalScrollLayout: boolean; + showMidiBindingsDialog: boolean; + screenHeight: number; +}; + + +export const MainPage = + withStyles(styles, { withTheme: true })( + class extends ResizeResponsiveComponent + { + model: PiPedalModel; + + constructor(props: MainProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.state = { + selectedPedal: -1, + loadDialogOpen: false, + pedalBoard: this.model.pedalBoard.get(), + addMenuAnchorEl: null, + splitControlBar: this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD, + horizontalScrollLayout: this.windowSize.height < HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK, + showMidiBindingsDialog: false, + screenHeight: this.windowSize.height, + + }; + this.onSelectionChanged = this.onSelectionChanged.bind(this); + this.onPedalDoubleClick = this.onPedalDoubleClick.bind(this); + this.onLoadClick = this.onLoadClick.bind(this); + this.onLoadOk = this.onLoadOk.bind(this); + this.onLoadCancel = this.onLoadCancel.bind(this); + this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this); + this.handleEnableCurrentItemChanged = this.handleEnableCurrentItemChanged.bind(this); + } + + onInsertPedal(instanceId: number) { + this.setAddMenuAnchorEl(null); + let newId = this.model.addPedalBoardItem(instanceId, false); + this.setSelection(newId); + } + onAppendPedal(instanceId: number) { + this.setAddMenuAnchorEl(null); + let newId = this.model.addPedalBoardItem(instanceId, true); + + this.setSelection(newId); + + } + onInsertSplit(instanceId: number) { + this.setAddMenuAnchorEl(null); + let newId = this.model.addPedalBoardSplitItem(instanceId, false); + this.setSelection(newId); + + } + onAppendSplit(instanceId: number) { + this.setAddMenuAnchorEl(null); + let newId = this.model.addPedalBoardSplitItem(instanceId, true); + this.setSelection(newId); + + } + setAddMenuAnchorEl(value: HTMLElement | null) { + this.setState({ addMenuAnchorEl: value }); + } + onAddClick(e: SyntheticEvent) { + this.setAddMenuAnchorEl(e.currentTarget as HTMLElement); + } + + handleMidiBindingsDialogClose() { + this.setState({ showMidiBindingsDialog: false }) + } + handleAddClose(): void { + this.setAddMenuAnchorEl(null); + } + + handleMidiConfiguration(instanceId: number): void { + this.setState({ showMidiBindingsDialog: true }); + } + handleEnableCurrentItemChanged(event: any): void { + let newValue = event.target.checked; + let item = this.getSelectedPedalBoardItem(); + if (item != null) { + this.model.setPedalBoardItemEnabled(item.getInstanceId(), newValue); + + } + } + handleSelectPluginPreset(instanceId: number, presetName: string) { + this.model.loadPluginPreset(instanceId, presetName); + } + onPedalBoardChanged(value: PedalBoard) { + this.setState({ pedalBoard: value }); + } + onDeletePedal(instanceId: number): void { + let result = this.model.deletePedalBoardPedal(instanceId); + if (result != null) { + this.setState({ selectedPedal: result }); + } + } + + componentDidMount() { + super.componentDidMount(); + this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged); + } + componentWillUnmount() { + this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged); + super.componentWillUnmount(); + } + updateResponsive() { + this.setState({ + splitControlBar: this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD, + horizontalScrollLayout: this.windowSize.height < HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK, + screenHeight: this.windowSize.height + }); + } + onWindowSizeChanged(width: number, height: number): void { + super.onWindowSizeChanged(width, height); + this.updateResponsive(); + } + + + setSelection(selectedId_: number): void { + this.setState({ selectedPedal: selectedId_ }); + } + + onSelectionChanged(selectedId: number): void { + this.setSelection(selectedId); + } + onPedalDoubleClick(selectedId: number): void { + this.setSelection(selectedId); + let item = this.getPedalBoardItem(selectedId); + if (item != null) { + if (item.isSplit()) { + let split = item as PedalBoardSplitItem; + if (split.getSplitType() === SplitType.Ab) { + let cv = split.getToggleAbControlValue(); + if (split.instanceId === undefined) throw new PiPedalStateError("Split without valid id."); + this.model.setPedalBoardControlValue(split.instanceId, cv.key, cv.value); + } + } else { + this.setState({ loadDialogOpen: true }); + } + } + } + onLoadCancel(): void { + this.setState({ loadDialogOpen: false }); + } + onLoadOk(selectedUri: string): void { + this.setState({ loadDialogOpen: false }); + let itemId = this.state.selectedPedal; + let newSelectedItem = this.model.loadPedalBoardPlugin(itemId, selectedUri); + this.setState({ selectedPedal: newSelectedItem }); + } + + onLoadClick(e: SyntheticEvent) { + this.setState({ loadDialogOpen: true }); + } + + getPedalBoardItem(selectedId?: number): PedalBoardItem | null { + if (selectedId === undefined) return null; + + let pedalBoard = this.model.pedalBoard.get(); + if (!pedalBoard) return null; + let it = pedalBoard.itemsGenerator(); + if (!selectedId) return null; + while (true) { + let v = it.next(); + if (v.done) break; + let item = v.value; + if (item.instanceId === selectedId) { + return item; + } + + } + return null; + + } + + onPedalboardPropertyChanged(instanceId: number, key: string, value: number) { + this.model.setPedalBoardControlValue(instanceId, key, value); + } + getSelectedPedalBoardItem(): PedalBoardItem | null { + return this.getPedalBoardItem(this.state.selectedPedal); + } + getSelectedUri(): string { + let pedalBoardItem = this.getSelectedPedalBoardItem(); + if (pedalBoardItem == null) return ""; + return pedalBoardItem.uri; + } + titleBar(pedalBoardItem: PedalBoardItem | null): React.ReactNode { + let title = ""; + let author = ""; + let pluginUri = ""; + let presetsUri = ""; + if (pedalBoardItem) { + if (pedalBoardItem.isEmpty()) { + title = ""; + } else if (pedalBoardItem.isSplit()) { + title = "Split"; + } else { + let uiPlugin = this.model.getUiPlugin(pedalBoardItem.uri); + if (uiPlugin == null) { + title = "Missing Plugin"; + } else { + title = uiPlugin.name; + author = uiPlugin.author_name; + presetsUri = uiPlugin.uri; + if (uiPlugin.description.length > 20) { + pluginUri = uiPlugin.uri; + } + } + } + } + let classes = this.props.classes; + return ( +
+
+ + {title} + + + {author} + +
+
+ +
+
+ this.handleSelectPluginPreset(pedalBoardItem!.instanceId, presetName)} + /> +
+
+ ); + } + + + render() { + let classes = this.props.classes; + let pedalBoard = this.model.pedalBoard.get(); + let pedalBoardItem = this.getSelectedPedalBoardItem(); + let uiPlugin = null; + let bypassVisible = false; + let bypassChecked = false; + let canDelete = false; + let canAdd = false; + let instanceId = -1; + + if (pedalBoardItem) { + canDelete = pedalBoard.canDeleteItem(pedalBoardItem.instanceId); + instanceId = pedalBoardItem.instanceId; + if (pedalBoardItem.isEmpty()) { + canAdd = true; + } else if (pedalBoardItem.isSplit()) { + canAdd = true; + } else { + uiPlugin = this.model.getUiPlugin(pedalBoardItem.uri); + canAdd = true; + if (uiPlugin) { + bypassVisible = true; + bypassChecked = pedalBoardItem.isEnabled; + } + } + } + let horizontalScrollLayout = this.state.horizontalScrollLayout; + + return ( +
+
+ +
+
+
+
+
+
+ +
+
+ { + (!this.state.splitControlBar) && this.titleBar(pedalBoardItem) + } +
+ +
+
+ { this.onAddClick(e) }} > + + + this.handleAddClose()} + TransitionComponent={Fade} + > + this.onInsertPedal(instanceId)}>Insert pedal + this.onAppendPedal(instanceId)}>Append pedal + + this.onInsertSplit(instanceId)}>Insert split + this.onAppendSplit(instanceId)}>Append split + +
+
+ { this.onDeletePedal(pedalBoardItem?.instanceId ?? -1) }} > + Delete + +
+
+ +
+
+ { this.handleMidiConfiguration(instanceId); }}> + Midi configuration + + +
+
+
+ { + this.state.splitControlBar && ( +
+ { + this.titleBar(pedalBoardItem) + } +
+ ) + } +
+ { + GetControlView(pedalBoardItem) + } + +
+ this.setState({showMidiBindingsDialog: false} ) } + /> + { + (this.state.loadDialogOpen) && ( + + + ) + } +
+ + ); + } + } + ); + +export default MainPage \ No newline at end of file diff --git a/react/src/MidiBinding.tsx b/react/src/MidiBinding.tsx new file mode 100644 index 0000000..88f0709 --- /dev/null +++ b/react/src/MidiBinding.tsx @@ -0,0 +1,60 @@ + + +export default class MidiBinding { + deserialize(input: any) : MidiBinding { + this.symbol = input.symbol; + this.bindingType = input.bindingType; + this.note = input.note; + this.control = input.control; + this.minValue = input.minValue; + this.maxValue = input.maxValue; + this.linearControlType = input.linearControlType; + this.switchControlType = input.switchControlType; + return this; + } + static deserialize_array(input: any): MidiBinding[] { + let result: MidiBinding[] = []; + for (let i = 0; i < input.length; ++i) + { + result.push(new MidiBinding().deserialize(input[i])); + } + return result; + + } + clone(): MidiBinding { return new MidiBinding().deserialize(this);} + equals(other: MidiBinding) : boolean + { + return (this.symbol === other.symbol) + && (this.bindingType === other.bindingType) + && (this.note === other.note) + && (this.control === other.control) + && (this.minValue === other.minValue) + && (this.maxValue === other.maxValue) + && (this.linearControlType === other.linearControlType) + && (this.switchControlType === other.switchControlType) + } + + static BINDING_TYPE_NONE: number = 0; + static BINDING_TYPE_NOTE: number = 1; + static BINDING_TYPE_CONTROL: number = 2; + + symbol: string = ""; + + bindingType: number = MidiBinding.BINDING_TYPE_NONE; + note: number = 12*4+24; // C4. + control: number = 1; + minValue: number = 0; + maxValue: number = 1; + rotaryScale: number = 1; + + static LINEAR_CONTROL_TYPE:number = 0; + static CIRCULAR_CONTROL_TYPE: number = 1; + + linearControlType: number = MidiBinding.LINEAR_CONTROL_TYPE; + + static LATCH_CONTROL_TYPE: number = 0; + static MOMENTARY_CONTROL_TYPE: number = 1; + + switchControlType: number = MidiBinding.LATCH_CONTROL_TYPE; + +}; \ No newline at end of file diff --git a/react/src/MidiBindingView.tsx b/react/src/MidiBindingView.tsx new file mode 100644 index 0000000..2bcb996 --- /dev/null +++ b/react/src/MidiBindingView.tsx @@ -0,0 +1,299 @@ +import { Component } from 'react'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import MenuItem from '@material-ui/core/MenuItem'; +import Select from '@material-ui/core/Select'; +import MidiBinding from './MidiBinding'; +import Utility, { nullCast } from './Utility'; +import Typography from '@material-ui/core/Typography'; +import MicNoneOutlinedIcon from '@material-ui/icons/MicNoneOutlined'; +import MicOutlinedIcon from '@material-ui/icons/MicOutlined'; +import IconButton from '@material-ui/core/IconButton'; +import NumericInput from './NumericInput'; + + + +const styles = (theme: Theme) => createStyles({ + controlDiv: { flex: "0 0 auto", marginRight: 12,verticalAlign: "center", height: 48, paddingTop: 8, paddingBottom: 8 }, + controlDiv2: { flex: "0 0 auto", marginRight: 12,verticalAlign: "center", + height: 48, paddingTop: 0, paddingBottom: 0, whiteSpace: "nowrap" } +}); + +interface MidiBindingViewProps extends WithStyles { + instanceId: number; + listen: boolean; + midiBinding: MidiBinding; + onChange: (instanceId: number, newBinding: MidiBinding) => void; + onListen: (instanceId: number, key: string, listenForControl: boolean) => void; +}; + + +interface MidiBindingViewState { +}; + + + + +const MidiBindingView = + withStyles(styles, { withTheme: true })( + class extends Component { + + model: PiPedalModel; + + constructor(props: MidiBindingViewProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + }; + } + + handleTypeChange(e: any, extra: any) { + let newValue = parseInt(e.target.value); + let newBinding = this.props.midiBinding.clone(); + newBinding.bindingType = newValue; + this.props.onChange(this.props.instanceId, newBinding); + } + handleNoteChange(e: any, extra: any) { + let newValue = parseInt(e.target.value); + let newBinding = this.props.midiBinding.clone(); + newBinding.note = newValue; + this.props.onChange(this.props.instanceId, newBinding); + } + handleControlChange(e: any, extra: any) { + let newValue = parseInt(e.target.value); + let newBinding = this.props.midiBinding.clone(); + newBinding.control = newValue; + this.props.onChange(this.props.instanceId, newBinding); + } + handleLatchControlTypeChange(e: any, extra: any) { + let newValue = parseInt(e.target.value); + let newBinding = this.props.midiBinding.clone(); + newBinding.switchControlType = newValue; + this.props.onChange(this.props.instanceId, newBinding); + } + handleLinearControlTypeChange(e: any, extra: any) { + let newValue = parseInt(e.target.value); + let newBinding = this.props.midiBinding.clone(); + newBinding.linearControlType = newValue; + this.props.onChange(this.props.instanceId, newBinding); + } + handleMinChange(value: number): void { + let newBinding = this.props.midiBinding.clone(); + newBinding.minValue = value; + this.props.onChange(this.props.instanceId, newBinding); + } + handleMaxChange(value: number): void { + let newBinding = this.props.midiBinding.clone(); + newBinding.maxValue = value; + this.props.onChange(this.props.instanceId, newBinding); + } + handleScaleChange(value: number): void { + let newBinding = this.props.midiBinding.clone(); + newBinding.rotaryScale = value; + this.props.onChange(this.props.instanceId, newBinding); + } + + + generateMidiSelects(): React.ReactNode[] { + let result: React.ReactNode[] = []; + + for (let i = 0; i < 127; ++i) { + result.push( + {Utility.midiNoteName(i)} + ) + } + + return result; + } + generateControlSelects(): React.ReactNode[] { + + return Utility.validMidiControllers.map((control) => ( + {control.displayName} + ) + ); + } + + + render() { + let classes = this.props.classes; + let midiBinding = this.props.midiBinding; + let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId); + let uiPlugin = this.model.getUiPlugin(pedalBoardItem.uri); + if (!uiPlugin) { + return (
); + } + + let canLatch: boolean = false; + let canTrigger: boolean = false; + let showLinearControlTypeSelect: boolean = false; + let isBinaryControl: boolean = false; + let showLinearRange: boolean = false; + let canRotaryScale: boolean = false; + if (this.props.midiBinding.symbol === "__bypass") { + isBinaryControl = true; + canLatch = midiBinding.bindingType !== MidiBinding.BINDING_TYPE_NONE; + } else { + let port = nullCast(uiPlugin!.getControl(this.props.midiBinding.symbol)); + isBinaryControl = (port.isAbToggle() || port.isOnOffSwitch()); + if (midiBinding.bindingType !== MidiBinding.BINDING_TYPE_NONE) { + canLatch = isBinaryControl; + canTrigger = port.trigger; + showLinearControlTypeSelect = !(canLatch || canTrigger); + showLinearRange = showLinearControlTypeSelect && midiBinding.linearControlType === MidiBinding.LINEAR_CONTROL_TYPE; + canRotaryScale = showLinearControlTypeSelect && midiBinding.linearControlType === MidiBinding.CIRCULAR_CONTROL_TYPE; + } + } + return ( +
+
+ +
+ { + (midiBinding.bindingType === MidiBinding.BINDING_TYPE_NOTE) && + ( +
+ + { + if (this.props.listen) + { + this.props.onListen(-2, "", false) + } else { + this.props.onListen(this.props.instanceId, this.props.midiBinding.symbol, false) + } + }}> + { this.props.listen ? ( + + ) : ( + + )} + +
+ ) + } + { + (midiBinding.bindingType === MidiBinding.BINDING_TYPE_CONTROL) && + ( +
+ + + { + if (this.props.listen) + { + this.props.onListen(-2, "", false) + } else { + this.props.onListen(this.props.instanceId, this.props.midiBinding.symbol, true) + } + }}> + { this.props.listen ? ( + + ) : ( + + )} + + +
+ ) + } + { + ((canLatch) && + ( +
+ +
+ )) + } + { + (canTrigger) && + ( +
+ (Trigger) +
+ ) + + } + { + (showLinearControlTypeSelect) && + ( +
+ +
+ + ) + } + { + showLinearRange && ( +
+ Min:  + { this.handleMinChange(value); } } + /> +
+ ) + } + { + showLinearRange && ( +
+ Max:  + { this.handleMaxChange(value); } } /> +
+ ) + } + { + canRotaryScale && ( +
+ Scale:  + { this.handleScaleChange(value); } } /> +
+ ) + } +
+ ) + + } + }); + +export default MidiBindingView; \ No newline at end of file diff --git a/react/src/MidiBindingsDialog.tsx b/react/src/MidiBindingsDialog.tsx new file mode 100644 index 0000000..a777929 --- /dev/null +++ b/react/src/MidiBindingsDialog.tsx @@ -0,0 +1,343 @@ +import React, { SyntheticEvent } from 'react'; +import Dialog from '@material-ui/core/Dialog'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import { PiPedalModel, PiPedalModelFactory, ListenHandle } from './PiPedalModel'; +import Typography from '@material-ui/core/Typography'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import IconButton from '@material-ui/core/IconButton'; +import MidiBinding from './MidiBinding'; +import MidiBindingView from './MidiBindingView'; +import Snackbar from '@material-ui/core/Snackbar'; + +const styles = (theme: Theme) => createStyles({ + dialogAppBar: { + position: 'relative', + top: 0, left: 0 + }, + dialogTitle: { + marginLeft: theme.spacing(2), + flex: "1 1 auto", + }, + pluginTable: { + border: "collapse", + width: "100%", + + }, + pluginHead: { + borderTop: "1pt #DDD solid", paddingLeft: 22, paddingRight: 22 + }, + bindingTd: { + verticalAlign: "top", + paddingLeft: 12, paddingBottom: 8 + }, + nameTd: { + paddingLeft: 48, + verticalAlign: "top", + paddingTop: 12 + }, +}); + + +export interface MidiBindingDialogProps extends WithStyles { + open: boolean, + onClose: () => void +}; + +export interface MidiBindingDialogState { + listenInstanceId: number; + listenSymbol: string; + listenSnackbarOpen: boolean; + +}; + +export const MidiBindingDialog = + withStyles(styles, { withTheme: true })( + class extends ResizeResponsiveComponent { + + model: PiPedalModel; + + constructor(props: MidiBindingDialogProps) { + super(props); + this.state = { + listenInstanceId: -2, + listenSymbol: "", + listenSnackbarOpen: false + }; + this.model = PiPedalModelFactory.getInstance(); + this.handlePopState = this.handlePopState.bind(this); + this.handleClose = this.handleClose.bind(this); + } + mounted: boolean = false; + + hasHooks: boolean = false; + + stateWasPopped: boolean = false; + handlePopState(e: any): any { + this.stateWasPopped = true; + let shouldClose = (!e.state); + if (shouldClose) { + this.props.onClose(); + } + } + handleClose() { + this.props.onClose(); + } + + listenTimeoutHandle?: NodeJS.Timeout; + + listenHandle?: ListenHandle; + + cancelListenForControl() { + if (this.listenTimeoutHandle) { + clearTimeout(this.listenTimeoutHandle); + this.listenTimeoutHandle = undefined; + } + if (this.listenHandle) + { + this.model.cancelListenForMidiEvent(this.listenHandle) + this.listenHandle = undefined; + } + + this.setState({ listenInstanceId: -2, listenSymbol: "" }); + + } + + handleListenSucceeded(instanceId: number, symbol: string, isNote: boolean, noteOrControl: number) + { + this.listenHandle = undefined; // (one-shot event) + this.cancelListenForControl(); + + let pedalBoard = this.model.pedalBoard.get(); + let item = pedalBoard.getItem(instanceId); + if (!item) return; + + let binding = item.getMidiBinding(symbol); + let newBinding = binding.clone(); + if (isNote) { + newBinding.bindingType = MidiBinding.BINDING_TYPE_NOTE; + newBinding.note = noteOrControl; + } else { + newBinding.bindingType = MidiBinding.BINDING_TYPE_CONTROL; + newBinding.control = noteOrControl; + } + + this.model.setMidiBinding(instanceId,newBinding); + } + + + handleListenForControl(instanceId: number, symbol: string, listenForControl: boolean): void { + this.cancelListenForControl(); + this.setState({ listenInstanceId: instanceId, listenSymbol: symbol, listenSnackbarOpen: true }); + this.listenTimeoutHandle = setTimeout(() => { + this.cancelListenForControl(); + }, 8000); + + this.listenHandle = this.model.listenForMidiEvent(listenForControl, + (isNote: boolean, noteOrControl: number) => { + this.handleListenSucceeded(instanceId,symbol,isNote, noteOrControl); + }); + + + + } + + updateHooks(): void { + let wantHooks = this.mounted && this.props.open; + if (wantHooks !== this.hasHooks) { + this.hasHooks = wantHooks; + + if (this.hasHooks) { + this.stateWasPopped = false; + window.addEventListener("popstate", this.handlePopState); + // eslint-disable-next-line no-restricted-globals + let state = history.state; + if (!state) { + state = {}; + } + state.midiBindingDialog = true; + + // eslint-disable-next-line no-restricted-globals + history.pushState( + state, + "Preset MIDI Bindings", + "#MidiBindingDialog" + ); + } else { + window.removeEventListener("popstate", this.handlePopState); + if (!this.stateWasPopped) { + // eslint-disable-next-line no-restricted-globals + history.back(); + } + this.cancelListenForControl(); + + } + + } + } + onWindowSizeChanged(width: number, height: number): void { + } + + + componentDidMount() { + super.componentDidMount(); + this.mounted = true; + this.updateHooks(); + } + componentWillUnmount() { + super.componentDidMount(); + + this.mounted = false; + this.updateHooks(); + + } + + componentDidUpdate() { + this.updateHooks(); + } + handleItemChanged(instanceId: number, newBinding: MidiBinding) { + this.model.setMidiBinding(instanceId, newBinding); + } + generateTable(): React.ReactNode[] { + let classes = this.props.classes; + let result: React.ReactNode[] = []; + + let pedalboard = this.model.pedalBoard.get(); + let iter = pedalboard.itemsGenerator(); + while (true) { + let v = iter.next(); + if (v.done) break; + let item = v.value; + + + let plugin = this.model.getUiPlugin(item.uri); + if (plugin) { + result.push( + + + + {plugin.name} + + + + ); + result.push( + + + + Bypass + + + + { + if (instanceId === -2) + { + this.cancelListenForControl(); + } else { + this.handleListenForControl(instanceId, symbol, listenForControl); + } + }} + listen={item.instanceId === this.state.listenInstanceId && this.state.listenSymbol === "__bypass"} + onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)} + /> + + + ); + + for (let i = 0; i < plugin.controls.length; ++i) { + let control = plugin.controls[i]; + let symbol = control.symbol; + result.push( + + + + {control.name} + + + + { + this.handleListenForControl(instanceId, symbol, listenForControl); + }} + + onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)} + /> + + + ); + } + } + + } + + + return result; + } + + supressDefault(e: SyntheticEvent) { + //e.preventDefault(); + //e.stopPropagation(); + } + + render() { + let props = this.props; + let { open, classes } = props; + if (!open) { + return (
); + } + + return ( + +
+
+ + + + + + + Preset MIDI Bindings + + + +
+
+ + + + + + + + {this.generateTable()} + + +
+
+
+ this.setState({ listenSnackbarOpen: false })} + message="Listening for MIDI input" + /> +
+ ); + } + }); + + +export default MidiBindingDialog; \ No newline at end of file diff --git a/react/src/NumericInput.tsx b/react/src/NumericInput.tsx new file mode 100644 index 0000000..da4f46d --- /dev/null +++ b/react/src/NumericInput.tsx @@ -0,0 +1,131 @@ +import React, { Component } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import Input from '@material-ui/core/Input'; + + + +const styles = ({ palette }: Theme) => createStyles({ + +}); + + + +interface NumericInputProps extends WithStyles { + ariaLabel: string; + defaultValue: number; + min: number; + max: number; + onChange: (value: number) => void; +}; + +interface NumericInputState { + error: boolean; +}; + +export const NumericInput = + withStyles(styles, { withTheme: true })( + class extends Component + { + + + constructor(props: NumericInputProps) { + super(props); + this.state = { + error: false + }; + } + + changed: boolean = false; + + handleChange(event: any): void { + this.changed = true; + let strValue = event.target.value; + try { + let value = Number(strValue); + if (isNaN(value)) + { + this.setState({ error: true }); + } else if (value >= this.props.min && value <= this.props.max) { + this.setState({ error: false }); + } else { + this.setState({ error: true }); + } + } catch (error) { + this.setState({ error: true }); + } + + } + + toDisplayValue(value: number): string { + if (value <= -1000 || value >= 1000) + { + return value.toFixed(0); + } + if (value <= -100 || value >= 100) + { + return value.toFixed(1); + } + if (value <= -10 || value >= 10) + { + return value.toFixed(2); + } else { + return value.toFixed(3); + } + } + + apply(input: HTMLInputElement) { + if (this.changed) { + let strValue = input.value; + let value = Number(strValue); + if (!isNaN(value)) + { + if (value < this.props.min) value = this.props.min; + if (value > this.props.max) value = this.props.max; + input.value = this.toDisplayValue(value); + this.props.onChange(value); + } else { + input.value = this.toDisplayValue(this.props.defaultValue); + } + this.changed = false; + this.setState({ error: false }); + } + } + + handleLostFocus(e: any) { + this.apply(e.currentTarget as HTMLInputElement); + } + handleKeyDown(e: React.KeyboardEvent) { + if (e.key === "Enter") + { + this.apply(e.currentTarget as HTMLInputElement); + } else if (e.key === "Escape") + { + e.currentTarget.value = this.toDisplayValue(this.props.defaultValue); + this.changed = false; + } + } + + + render() { + //let classes = this.props.classes; + return ( this.handleLostFocus(e), + "onKeyDown": (e: any) => this.handleKeyDown(e) + }} + onChange={(event) => this.handleChange(event)} + defaultValue={this.toDisplayValue(this.props.defaultValue)} + error={this.state.error} + /> + + ); + } + } + ); + +export default NumericInput; + + + diff --git a/react/src/ObservableProperty.tsx b/react/src/ObservableProperty.tsx new file mode 100644 index 0000000..9f46687 --- /dev/null +++ b/react/src/ObservableProperty.tsx @@ -0,0 +1,50 @@ + + +export type OnChangedHandler = (newValue: VALUE_TYPE) => void; + + +export class ObservableProperty { + + _value_type: VALUE_TYPE; + _on_changed_handlers: OnChangedHandler[] = []; + + constructor(default_value: VALUE_TYPE) + { + this._value_type = default_value; + } + + addOnChangedHandler(handler: OnChangedHandler ) : void + { + this._on_changed_handlers.push(handler); + handler(this._value_type); + } + removeOnChangedHandler(handler: OnChangedHandler ) : void + { + let oldArray = this._on_changed_handlers; + + let newArray: OnChangedHandler[] = []; + + let outIx = 0; + for (let i = 0; i < oldArray.length; ++i) + { + if (oldArray[i] !== handler) + { + newArray[outIx++] = oldArray[i]; + } + } + this._on_changed_handlers = newArray; + } + + get() : VALUE_TYPE { + return this._value_type; + } + + set(value: VALUE_TYPE) : void + { + this._value_type = value; + + let t = this._on_changed_handlers; // take an copy in case removes happen while iteratiing. + t.forEach(c => c(value)); + } + +}; \ No newline at end of file diff --git a/react/src/Pedal.tsx b/react/src/Pedal.tsx new file mode 100644 index 0000000..2e43f73 --- /dev/null +++ b/react/src/Pedal.tsx @@ -0,0 +1,40 @@ +import React, { Component, ReactNode } from 'react'; +import { withStyles, createStyles, WithStyles } from '@material-ui/core'; +import { Theme } from '@material-ui/core/styles/createMuiTheme'; +import { Lv2Plugin } from './Lv2Plugin' + + + +const pedalStyles = ({ palette }: Theme) => createStyles({ +}); + +interface PedalProps extends WithStyles { + plugin: Lv2Plugin; + children?: React.ReactChild | React.ReactChild[]; + +}; + +type PedalState = { + +}; + +export const TemporaryDrawer = withStyles(pedalStyles)( + class extends Component + { + state: PedalState; + + constructor(props: PedalProps) { + super(props); + this.state = { + }; + } + render() : ReactNode { + return ( +
+ +
+ ); + } + + } +); \ No newline at end of file diff --git a/react/src/PedalBoard.tsx b/react/src/PedalBoard.tsx new file mode 100644 index 0000000..9f90f09 --- /dev/null +++ b/react/src/PedalBoard.tsx @@ -0,0 +1,570 @@ +import { PiPedalArgumentError } from './PiPedalError'; +import MidiBinding from './MidiBinding'; + + +const SPLIT_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#Split"; +const EMPTY_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#Empty"; + + +interface Deserializable { + deserialize(input: any): T; +} + +export class ControlValue implements Deserializable { + constructor(key?: string, value?: number) + { + this.key = key??""; + this.value = value?? 0; + } + deserialize(input: any): ControlValue { + this.key = input.key; + this.value = input.value; + return this; + } + static EmptyArray: ControlValue[] = []; + + static deserializeArray(input: any[]): ControlValue[] { + let result: ControlValue[] = []; + for (let i = 0; i < input.length; ++i) { + result[i] = new ControlValue().deserialize(input[i]); + } + return result; + } + setValue(value: number) { + this.value = value; + } + + key: string; + value: number; + +} + +export class PedalBoardItem implements Deserializable { + deserializePedalBoardItem(input: any): PedalBoardItem { + this.instanceId = input.instanceId ?? -1; + this.uri = input.uri; + this.pluginName = input.pluginName; + this.isEnabled = input.isEnabled; + this.midiBindings = MidiBinding.deserialize_array(input.midiBindings); + + this.controlValues = ControlValue.deserializeArray(input.controlValues); + return this; + } + deserialize(input: any): PedalBoardItem { + return this.deserializePedalBoardItem(input); + } + static deserializeArray(input: any): PedalBoardItem[] { + let result: PedalBoardItem[] = []; + for (let i = 0; i < input.length; ++i) { + let inputItem: any = input[i]; + let uri: string = inputItem.uri as string; + let outputItem: PedalBoardItem; + + if (uri === SPLIT_PEDALBOARD_ITEM_URI) { + outputItem = new PedalBoardSplitItem().deserialize(inputItem); + } else { + outputItem = new PedalBoardItem().deserialize(inputItem); + } + result[i] = outputItem; + + } + return result; + } + + getInstanceId() : number { + if (this.instanceId === undefined) + { + throw new PiPedalArgumentError("Item does not have an id."); + } + return this.instanceId; + } + isEmpty(): boolean { + return this.uri === EMPTY_PEDALBOARD_ITEM_URI; + } + isSplit(): boolean { + return this.uri === SPLIT_PEDALBOARD_ITEM_URI; + } + + getControl(key: string): ControlValue { + for (let i = 0; i < this.controlValues.length; ++i) { + let v = this.controlValues[i]; + if (v.key === key) { + return v; + } + } + throw new PiPedalArgumentError("Invalid key."); + + } + + getControlValue(key: string): number { + for (let i = 0; i < this.controlValues.length; ++i) { + let v = this.controlValues[i]; + if (v.key === key) { + return v.value; + } + } + return 0; + } + setControlValue(key: string, value: number): boolean { + for (let i = 0; i < this.controlValues.length; ++i) { + let v = this.controlValues[i]; + if (v.key === key) { + if (v.value === value) return false; + v.setValue(value); + return true; + } + } + throw new PiPedalArgumentError("Control not found."); + } + setMidiBinding(midiBinding: MidiBinding): boolean { + if (this.midiBindings) + { + for (let i = 0; i < this.midiBindings.length; ++i) + { + let binding = this.midiBindings[i]; + if (midiBinding.symbol === binding.symbol) + { + if (binding.equals(midiBinding)) + { + return false; + } + this.midiBindings.splice(i,1,midiBinding); + return true; + } + } + this.midiBindings.push(midiBinding); + return true; + } + this.midiBindings = [ midiBinding]; + return true; + } + getMidiBinding(symbol: string): MidiBinding { + if (this.midiBindings) + { + for (let i = 0; i < this.midiBindings.length; ++i) + { + let midiBinding = this.midiBindings[i]; + if (midiBinding.symbol === symbol) + { + return midiBinding; + } + } + } + let result = new MidiBinding(); + result.symbol = symbol; + return result; + } + + + static EmptyArray: PedalBoardItem[] = []; + + instanceId: number = -1; + isEnabled: boolean = false; + uri: string = ""; + pluginName?: string; + controlValues: ControlValue[] = ControlValue.EmptyArray; + midiBindings: MidiBinding[] = []; +}; + + +export enum SplitType { + Ab = 0, + Mix = 1, + Lr = 2 +} + + + +export class PedalBoardSplitItem extends PedalBoardItem { + static PANL_KEY: string = "panL"; + static PANR_KEY: string = "panR"; + static VOLL_KEY: string = "volL"; + static VOLR_KEY: string = "volR"; + + static MIX_KEY: string = "mix"; + static TYPE_KEY: string = "splitType"; + static SELECT_KEY: string = "select"; + + + deserialize(input: any): PedalBoardSplitItem { + this.deserializePedalBoardItem(input); + this.topChain = PedalBoardItem.deserializeArray(input.topChain); + this.bottomChain = PedalBoardItem.deserializeArray(input.bottomChain); + + return this; + } + getSplitType(): SplitType { + let rawValue = this.getControlValue(PedalBoardSplitItem.TYPE_KEY); + + if (rawValue < 1) return SplitType.Ab; + if (rawValue < 2) return SplitType.Mix; + return SplitType.Lr; + } + getToggleAbControlValue(): ControlValue { + let cv = new ControlValue(); + cv.key = "select"; + cv.value = this.isASelected() ? 1 : 0; + return cv; + + } + getMixControl(): ControlValue { + return this.getControl(PedalBoardSplitItem.MIX_KEY); + } + getMix(): number { + return this.getControlValue(PedalBoardSplitItem.MIX_KEY); + } + isASelected(): boolean { + return this.getSplitType() !== SplitType.Ab || this.getControlValue(PedalBoardSplitItem.SELECT_KEY) === 0; + } + isBSelected(): boolean { + return this.getSplitType() !== SplitType.Ab || this.getControlValue(PedalBoardSplitItem.SELECT_KEY) !== 0; + } + + topChain: PedalBoardItem[] = PedalBoardItem.EmptyArray; + bottomChain: PedalBoardItem[] = PedalBoardItem.EmptyArray; +} + + + + + +export class PedalBoard implements Deserializable { + + deserialize(input: any): PedalBoard { + this.name = input.name; + this.items = PedalBoardItem.deserializeArray(input.items); + this.nextInstanceId = input.nextInstanceId ?? -1; + return this; + } + + clone(): PedalBoard { + return new PedalBoard().deserialize(this); + } + name: string = ""; + items: PedalBoardItem[] = []; + nextInstanceId: number = -1; + + *itemsGenerator(): Generator { + let it = itemGenerator_(this.items); + while (true) + { + let v = it.next(); + if (v.done) break; + yield v.value; + } + } + maybeGetItem(instanceId: number): PedalBoardItem | null{ + let it = this.itemsGenerator(); + while (true) + { + let v = it.next(); + if (v.done) break; + if (v.value.instanceId === instanceId) + { + return v.value; + } + } + return null; + } + getItem(instanceId: number): PedalBoardItem { + let it = this.itemsGenerator(); + while (true) + { + let v = it.next(); + if (v.done) break; + if (v.value.instanceId === instanceId) + { + return v.value; + } + } + throw new PiPedalArgumentError("Item not found."); + } + deleteItem_(instanceId: number,items: PedalBoardItem[]): number | null + { + for (let i = 0; i < items.length; ++i) + { + let item = items[i]; + if (item.instanceId === instanceId) + { + if (items.length > 1) { + items.splice(i,1); + let nextSelectedItem = i; + if (i >= items.length) --nextSelectedItem; + return items[nextSelectedItem].instanceId; + } else { + // replace with an empty item. + let newItem = this.createEmptyItem(); + items[i] = newItem; + return newItem.instanceId; + + } + } else { + if (item.isSplit()) + { + let splitItem = item as PedalBoardSplitItem; + let t = this.deleteItem_(instanceId,splitItem.topChain); + if (t != null) return t; + + t = this.deleteItem_(instanceId,splitItem.bottomChain); + if (t != null) return t; + } + } + } + return null; + } + + canDeleteItem_(instanceId: number,items: PedalBoardItem[]): boolean + { + for (let i = 0; i < items.length; ++i) + { + let item = items[i]; + if (item.instanceId === instanceId) + { + if (items.length > 1) return true; + return !item.isEmpty(); // can delete if there's one non-empty item. + } + if (item.isSplit()) + { + let splitItem = item as PedalBoardSplitItem; + if (this.canDeleteItem_(instanceId,splitItem.topChain)) + { + return true; + } + if (this.canDeleteItem_(instanceId,splitItem.bottomChain)) + { + return true; + } + } + } + return false; + } + + canDeleteItem(instanceId: number): boolean + { + return this.canDeleteItem_(instanceId,this.items); + } + // Returns the next selected instanceId, or null if no deletion occurred. + deleteItem(instanceId: number): number | null { + return this.deleteItem_(instanceId,this.items); + } + + setMidiBinding(instanceId: number, midiBinding: MidiBinding): boolean + { + let item = this.getItem(instanceId); + if (!item) return false; + return item.setMidiBinding(midiBinding); + } + addToStart(item: PedalBoardItem) + { + this.items.splice(0,0,item); + } + addToEnd(item: PedalBoardItem) + { + this.items.splice(this.items.length,0,item); + } + static _addRelative(items: PedalBoardItem[],newItem: PedalBoardItem, instanceId: number, addBefore: boolean): boolean + { + for (let i = 0; i < items.length; ++i) + { + let item = items[i]; + if (item.instanceId === instanceId) + { + if (addBefore) + { + items.splice(i,0,newItem); + } else { + items.splice(i+1,0,newItem); + } + return true; + } + if (item.isSplit()) + { + let split = item as PedalBoardSplitItem; + if (this._addRelative(split.topChain,newItem,instanceId,addBefore)) + { + return true; + } + if (this._addRelative(split.bottomChain,newItem,instanceId,addBefore)) + { + return true; + } + } + } + return false; + + } + + addBefore(item: PedalBoardItem, instanceId: number) + { + if (item.instanceId === instanceId) return; + let result = PedalBoard._addRelative(this.items,item, instanceId, true); + if (!result) { + throw new PiPedalArgumentError("instanceId not found."); + } + + } + addAfter(item: PedalBoardItem, instanceId: number) + { + if (item.instanceId === instanceId) return; + let result = PedalBoard._addRelative(this.items,item, instanceId, false); + if (!result) { + throw new PiPedalArgumentError("instanceId not found."); + } + + } + + ensurePedalboardIds() { + if (this.nextInstanceId === -1) { + let minId = 1; + let it = this.itemsGenerator(); + while (true) { + let v = it.next(); + if (v.done) break; + if (v.value.instanceId) { + let t = v.value.instanceId; + if (t+1 > minId) minId = t+1; + } + + } + this.nextInstanceId = minId; + } + let it = this.itemsGenerator(); + while (true) { + let v = it.next(); + if (v.done) break; + if (v.value.instanceId === -1) { + v.value.instanceId = ++this.nextInstanceId; + + } + } + } + createEmptySplit(): PedalBoardSplitItem { + let result: PedalBoardSplitItem = new PedalBoardSplitItem(); + result.uri = SPLIT_PEDALBOARD_ITEM_URI; + result.instanceId = ++this.nextInstanceId; + result.pluginName = ""; + result.isEnabled = true; + result.topChain = [ this.createEmptyItem()]; + result.bottomChain = [ this.createEmptyItem()]; + result.controlValues = [ + new ControlValue(PedalBoardSplitItem.TYPE_KEY, 0), + new ControlValue(PedalBoardSplitItem.SELECT_KEY,0), + new ControlValue(PedalBoardSplitItem.MIX_KEY,0), + new ControlValue(PedalBoardSplitItem.PANL_KEY,0), + new ControlValue(PedalBoardSplitItem.VOLL_KEY,-3), + new ControlValue(PedalBoardSplitItem.PANR_KEY,0), + new ControlValue(PedalBoardSplitItem.VOLR_KEY,-3) + ]; + + + return result; + + + } + createEmptyItem(): PedalBoardItem { + let result: PedalBoardItem = new PedalBoardItem(); + result.uri = EMPTY_PEDALBOARD_ITEM_URI; + result.instanceId = ++this.nextInstanceId; + result.pluginName = ""; + result.isEnabled = true; + + return result; + } + setItemEmpty(item: PedalBoardItem) + { + item.uri = EMPTY_PEDALBOARD_ITEM_URI; + item.instanceId = ++this.nextInstanceId; + item.pluginName = ""; + item.isEnabled = true; + item.controlValues = []; + + } + + _replaceItem(items: PedalBoardItem[], instanceId: number, newItem: PedalBoardItem): boolean { + for (let i = 0; i < items.length; ++i) + { + let item = items[i]; + if (item.instanceId === instanceId) + { + items[i] = newItem; + return true; + } + if (items[i].isSplit()) + { + let splitItem = item as PedalBoardSplitItem; + if (this._replaceItem(splitItem.topChain,instanceId,newItem)) + return true; + if (this._replaceItem(splitItem.bottomChain,instanceId,newItem)) + { + return true; + } + } + } + return false; + } + + replaceItem(instanceId: number, newItem: PedalBoardItem) + { + let result = this._replaceItem(this.items,instanceId,newItem); + if (!result) + { + throw new PiPedalArgumentError("instanceId not found."); + } + } + _addItem(items: PedalBoardItem[], newItem: PedalBoardItem, instanceId: number, append: boolean) + { + for (let i = 0; i < items.length; ++i) + { + let item = items[i]; + if (item.instanceId === instanceId) + { + if (append) + { + items.splice(i+1,0,newItem); + return true; + } else { + items.splice(i,0,newItem); + return true; + } + } + if (item.isSplit()) + { + let splitItem = item as PedalBoardSplitItem; + if (this._addItem(splitItem.topChain,newItem,instanceId,append)) return true; + if (this._addItem(splitItem.bottomChain,newItem,instanceId,append)) return true; + } + } + } + + addItem(newItem: PedalBoardItem, instanceId: number, append: boolean): void + { + this._addItem(this.items,newItem,instanceId,append); + } + +} + +function* itemGenerator_(items: PedalBoardItem[]): Generator { + for (let i = 0; i < items.length; ++i) { + let item = items[i]; + yield item; + if (item.uri === SPLIT_PEDALBOARD_ITEM_URI) { + + let splitItem = item as PedalBoardSplitItem; + + let it = itemGenerator_(splitItem.topChain); + while (true) { + let v = it.next(); + if (v.done) break; + yield v.value; + } + it = itemGenerator_(splitItem.bottomChain); + while (true) { + let v = it.next(); + if (v.done) break; + yield v.value; + } + } + } +} + + diff --git a/react/src/PedalBoardView.tsx b/react/src/PedalBoardView.tsx new file mode 100644 index 0000000..8a08f91 --- /dev/null +++ b/react/src/PedalBoardView.tsx @@ -0,0 +1,1123 @@ +import React, { ReactNode, Component, SyntheticEvent } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { PluginType } from './Lv2Plugin'; +import ButtonBase from '@material-ui/core/ButtonBase'; +import Typography from '@material-ui/core/Typography'; +import { SelectIcon } from './PluginIcon'; +import { SelectHoverBackground } from './SelectHoverBackground'; +import SvgPathBuilder from './SvgPathBuilder'; +import Draggable from './Draggable' +import Rect from './Rect'; +import {PiPedalStateError} from './PiPedalError'; + + +import { + PedalBoard, PedalBoardItem, PedalBoardSplitItem, SplitType, +} from './PedalBoard'; + +const START_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#Start"; +const END_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#End"; + +const ENABLED_CONNECTOR_COLOR = "#666"; +const DISABLED_CONNECTOR_COLOR = "#CCC"; + + +const CELL_WIDTH: number = 96; +const CELL_HEIGHT: number = 64; +const FRAME_SIZE: number = 36; + +const STROKE_WIDTH = 3; +const STEREO_STROKE_WIDTH = 6; + +const SVG_STROKE_WIDTH = "3"; +const SVG_STEREO_STROKE_WIDTH = "6"; + + + +const EMPTY_ICON_URL = "img/fx_empty.svg"; +const TERMINAL_ICON_URL = "img/fx_terminal.svg"; + + +const pedalBoardStyles = (theme: Theme) => createStyles({ + scrollContainer: { + }, + + container: { + position: "relative", + overflow: "visible", + + }, + startItem: { + position: "absolute", + display: "flex", + alignItems: "center", + justifyContent: "center", + + width: CELL_WIDTH, + height: CELL_HEIGHT + + }, + endItem: { + position: "absolute", + display: "flex", + alignItems: "center", + justifyContent: "center", + + width: CELL_WIDTH, + height: CELL_HEIGHT + + }, + splitItem: { + position: "absolute", + display: "flex", + alignItems: "center", + justifyContent: "center", + + + width: CELL_WIDTH, + height: CELL_HEIGHT + + }, + splitStart: { + position: "absolute", + display: "flex", + width: CELL_WIDTH, + height: CELL_HEIGHT, + left: 0, + top: 0 + }, + splitEnd: { + position: "absolute", + display: "flex", + width: CELL_WIDTH, + height: CELL_HEIGHT, + right: 0, + top: 0 + }, + + pedalItem: { + position: "absolute", + width: CELL_WIDTH, + height: CELL_HEIGHT, + display: "flex", + alignItems: "center", + justifyContent: "center", + }, + iconFrame: { + + display: "flex", + alignItems: "center", + justifyContent: "center", + + background: theme.palette.background.paper, + marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2, + marginRight: (CELL_WIDTH - FRAME_SIZE) / 2, + marginTop: (CELL_HEIGHT - FRAME_SIZE) / 2, + marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2, + width: FRAME_SIZE, + height: FRAME_SIZE, + border: "1pt black solid", + borderRadius: 6 + }, + pedalIcon: { + width: 24, + height: 24, + opacity: 0.8 + }, + connector: { + position: "absolute", + width: CELL_WIDTH, + height: CELL_HEIGHT + }, + stroke: { + position: "absolute", + background: "#888" + }, + stereoStrokeOuter: { + position: "absolute", + background: "#888" + }, + stereoStrokeInner: { + position: "absolute", + background: "#888" + }, + +}); + +export type OnSelectHandler = (selectedPedal: number) => void; + +interface PedalBoardProps extends WithStyles { + theme: Theme; + selectedId?: number; + onSelectionChanged?: OnSelectHandler; + onDoubleClick?: OnSelectHandler; + hasTinyToolBar: boolean; + +}; +interface LayoutSize { + width: number; + height: number; +}; + +type PedalBoardState = { + pedalBoard?: PedalBoard; +}; + +const EMPTY_PEDALS: PedalLayout[] = []; + + +function makeChain(model: PiPedalModel, uiItems?: PedalBoardItem[]): PedalLayout[] { + let result: PedalLayout[] = []; + if (uiItems) { + for (let i = 0; i < uiItems.length; ++i) { + let item = uiItems[i]; + result.push(new PedalLayout(model, item)); + } + } + return result; +} + +class PedalLayout { + uri: string = ""; + name: string = ""; + pluginType: PluginType = PluginType.Plugin; + iconUrl: string = ""; + + bounds: Rect = new Rect(); + + inputs: number = 0; + outputs: number = 0; + stereoInput: boolean = false; + stereoOutput: boolean = false; + pedalItem?: PedalBoardItem; + + // Split Layout only. + topChildren: PedalLayout[] = EMPTY_PEDALS; + bottomChildren: PedalLayout[] = EMPTY_PEDALS; + topConnectorY: number = 0; + bottomConnectorY: number = 0; + + + static Start(): PedalLayout { + let t: PedalLayout = new PedalLayout(); + t.uri = START_PEDALBOARD_ITEM_URI; + t.iconUrl = TERMINAL_ICON_URL; + t.inputs = 0; + t.outputs = 1; + return t; + } + static End(): PedalLayout { + let t: PedalLayout = new PedalLayout(); + t.pluginType = PluginType.UtilityPlugin; + t.uri = END_PEDALBOARD_ITEM_URI; + t.iconUrl = TERMINAL_ICON_URL; + t.inputs = 2; + t.outputs = 0; + return t; + } + constructor(model?: PiPedalModel, pedalItem?: PedalBoardItem) { + if (model === undefined && pedalItem === undefined) { + return; + } + if (model === undefined || pedalItem === undefined) { + throw new Error("Invalid arguments."); + } + this.pedalItem = pedalItem; + this.uri = pedalItem.uri; + if (pedalItem.isSplit()) { + let splitter = pedalItem as PedalBoardSplitItem; + + this.pluginType = PluginType.UtilityPlugin; + this.topChildren = makeChain(model, splitter.topChain); + this.bottomChildren = makeChain(model, splitter.bottomChain); + + this.inputs = 2; + this.outputs = 2; + + } else if (pedalItem.isEmpty()) { + + this.pluginType = PluginType.UtilityPlugin; + this.iconUrl = EMPTY_ICON_URL; + this.inputs = 2; + this.outputs = 2; + + } else if (pedalItem.uri === START_PEDALBOARD_ITEM_URI) { + this.pluginType = PluginType.UtilityPlugin; + this.iconUrl = TERMINAL_ICON_URL; + this.inputs = 0; + this.outputs = PiPedalModelFactory.getInstance().jackSettings.get().inputAudioPorts.length; + + } else if (pedalItem.uri === END_PEDALBOARD_ITEM_URI) { + this.pluginType = PluginType.UtilityPlugin; + this.iconUrl = TERMINAL_ICON_URL; + this.inputs = PiPedalModelFactory.getInstance().jackSettings.get().outputAudioPorts.length; + this.outputs = 0; + } + else { + let uiPlugin = model.getUiPlugin(pedalItem.uri); + if (uiPlugin != null) { + this.pluginType = uiPlugin.plugin_type; + this.iconUrl = SelectIcon(uiPlugin.plugin_type,uiPlugin.uri); + this.name = uiPlugin.name; + this.inputs = uiPlugin.audio_inputs; + this.outputs = uiPlugin.audio_outputs; + } else { + // default to empty plugin. + this.pluginType = PluginType.UtilityPlugin; + this.name = "#Missing"; + this.iconUrl = EMPTY_ICON_URL; + this.inputs = 2; + this.outputs = 2; + } + } + } + isEmpty(): boolean { + return (!this.pedalItem) || this.pedalItem.isEmpty(); + } + isSplitter(): boolean { + return this.pedalItem !== undefined && this.pedalItem.isSplit(); + } + isStart() { + return this.uri === START_PEDALBOARD_ITEM_URI; + } + isEnd() { + return this.uri === END_PEDALBOARD_ITEM_URI; + } +} + +function* chainIterator(layoutChain: PedalLayout[]): Generator { + for (let i = 0; i < layoutChain.length; ++i) { + let item = layoutChain[i]; + yield item; + if (item.isSplitter()) { + let g = chainIterator(item.topChildren); + while (true) { + let v = g.next(); + if (v.done) { + break; + } + yield v.value; + } + g = chainIterator(item.bottomChildren); + while (true) { + let v = g.next(); + if (v.done) { + break; + } + yield v.value; + } + } + } + return; +} + + + +class LayoutParams { + nextId: number = 1; + cx: number = 0; + cy: number = 0; +} + + +const PedalBoardView = + withStyles(pedalBoardStyles, { withTheme: true })( + class extends Component + { + model: PiPedalModel; + + frameRef: React.RefObject; + scrollRef: React.RefObject; + + + constructor(props: PedalBoardProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + if (!props.selectedId) props.selectedId = -1; + this.state = { + pedalBoard: this.model.pedalBoard.get(), + }; + this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this); + this.frameRef = React.createRef(); + this.scrollRef = React.createRef(); + this.handleTouchStart = this.handleTouchStart.bind(this); + } + + handleTouchStart(e: any) + { + // just has to exist to allow Draggable to receive + // touchyMove. :-/ + } + + onDragEnd(instanceId: number, clientX: number, clientY: number) { + if (!this.currentLayout) return; + + if (!this.frameRef.current) return; + + let currentLayout: PedalLayout[] = this.currentLayout; + let frameElement = this.frameRef.current; + + let rc = frameElement.getBoundingClientRect(); + clientX -= rc.left; + clientY -= rc.top; + + let it = chainIterator(currentLayout); + + while (true) { + let v = it.next(); + if (v.done) break; + let item = v.value; + + if (item.isSplitter() && item.pedalItem) { + if (item.bounds.contains(clientX, clientY)) { + if (clientX < item.bounds.x + CELL_WIDTH / 2) { + this.model.movePedalBoardItemBefore(instanceId, item.pedalItem.instanceId); + this.setSelection(instanceId); + return; + } else if (clientX > item.bounds.right - CELL_WIDTH / 2) { + this.model.movePedalBoardItemAfter(instanceId, item.pedalItem.instanceId); + this.setSelection(instanceId); + return; + + } + } + let yMid = (item.bounds.y + item.bounds.bottom) / 2; + if (clientX >= item.bounds.x + && clientY < yMid && clientY >= item.topChildren[0].bounds.y + + ) { + if (clientX < item.topChildren[0].bounds.x) { + let topPedalItem = item.topChildren[0].pedalItem; + if (topPedalItem) { + this.model.movePedalBoardItemBefore(instanceId, topPedalItem.instanceId); + this.setSelection(instanceId); + return; + } + } + let lastTop = item.topChildren[item.topChildren.length - 1]; + if (clientX >= lastTop.bounds.right && clientX < item.bounds.right - CELL_WIDTH / 2) { + if (lastTop.pedalItem) { + this.model.movePedalBoardItemAfter(instanceId, lastTop.pedalItem.instanceId); + this.setSelection(instanceId); + return; + } + } + + } + if (clientX >= item.bounds.x + && clientY > yMid && clientY < item.bottomChildren[0].bounds.bottom + ) { + if (clientX < item.bottomChildren[0].bounds.x) { + let bottomPedalItem = item.bottomChildren[0].pedalItem; + if (bottomPedalItem) { + this.model.movePedalBoardItemBefore(instanceId, bottomPedalItem.instanceId); + this.setSelection(instanceId); + return; + } + } + let lastBottom = item.bottomChildren[item.bottomChildren.length-1]; + if (clientX >= lastBottom.bounds.right && clientX < item.bounds.right-CELL_WIDTH/2) + { + if (lastBottom.pedalItem) { + this.model.movePedalBoardItemAfter(instanceId, lastBottom.pedalItem.instanceId); + this.setSelection(instanceId); + return; + } + + } + + } + + } else if (item.bounds.contains(clientX, clientY)) { + if (item.isStart()) { + this.model.movePedalBoardItemToStart(instanceId); + this.setSelection(instanceId); + return; + } else if (item.isEnd()) { + this.model.movePedalBoardItemToEnd(instanceId); + this.setSelection(instanceId); + return; + } else { + if (item.pedalItem) + { + let margin = (CELL_WIDTH - FRAME_SIZE) / 2; + if (clientX < item.bounds.x + margin) { + this.model.movePedalBoardItemBefore(instanceId, item.pedalItem.instanceId); + } else if (clientX > item.bounds.right - margin) { + this.model.movePedalBoardItemAfter(instanceId, item.pedalItem.instanceId); + } else { + this.model.movePedalBoardItem(instanceId, item.pedalItem.instanceId); + } + this.setSelection(instanceId); + return; + } + } + + } + } + // delete the plugin. + let newId = this.model.setPedalBoardItemEmpty(instanceId); + this.setSelection(newId); + + } + + onPedalBoardChanged(value?: PedalBoard) { + this.setState({ pedalBoard: value }); + } + + componentDidMount() { + this.scrollRef.current!.addEventListener("touchstart",this.handleTouchStart, {passive: false}); + this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged); + + } + componentWillUnmount() { + this.scrollRef.current!.removeEventListener("touchstart",this.handleTouchStart); + this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged); + } + + offsetLayout_(layoutItems: PedalLayout[], offset: number): void { + for (let i = 0; i < layoutItems.length; ++i) { + let layoutItem = layoutItems[i]; + layoutItem.bounds.y += offset; + if (layoutItem.isSplitter()) { + layoutItem.topConnectorY += offset; + layoutItem.bottomConnectorY += offset; + this.offsetLayout_(layoutItem.topChildren, offset); + this.offsetLayout_(layoutItem.bottomChildren, offset); + } + } + } + + getSplitterIcon(layoutItem: PedalLayout) { + if (layoutItem.pedalItem === undefined) { + throw new Error("Invalid splitter"); + } + let split = layoutItem.pedalItem as PedalBoardSplitItem; + if (split.getSplitType() === SplitType.Ab) { + if (split.isASelected()) { + return "img/fx_split_a.svg"; + } else { + return "img/fx_split_b.svg"; + + } + } else if (split.getSplitType() === SplitType.Mix) { + return "img/fx_dial.svg"; + } else { + return "img/fx_lr.svg"; + } + } + + doLayout2_(lp: LayoutParams, layoutItems: PedalLayout[]): Rect { + let bounds = new Rect(); + for (let i = 0; i < layoutItems.length; ++i) { + let layoutItem = layoutItems[i]; + if (layoutItem.isSplitter()) { + let x0 = lp.cx; + let y0 = lp.cy; + + layoutItem.bounds.x = x0; + layoutItem.bounds.y = y0; + layoutItem.bounds.height = CELL_HEIGHT; + layoutItem.bounds.width = CELL_WIDTH; + + lp.cx += CELL_WIDTH; + + + let topBounds = this.doLayout2_(lp, layoutItem.topChildren); + if (topBounds.isEmpty()) { + topBounds.x = lp.cx; + topBounds.width = 0; + topBounds.y = y0 - CELL_HEIGHT / 2; + topBounds.height = CELL_HEIGHT; + + } + + + let dyTop = (lp.cy + CELL_HEIGHT / 2)- (topBounds.y + topBounds.height) ; + + + + this.offsetLayout_(layoutItem.topChildren, dyTop); + topBounds.offset(0, dyTop); + bounds.accumulate(topBounds); + + let topCx = lp.cx; + lp.cx = x0; + lp.cx += CELL_WIDTH; + + let bottomBounds = this.doLayout2_(lp, layoutItem.bottomChildren); + if (bottomBounds.isEmpty()) { + bottomBounds.x = lp.cx; bottomBounds.width = 0; + bottomBounds.y = lp.cy; bottomBounds.height = CELL_HEIGHT; + } + + let dyBottom = (lp.cy+CELL_HEIGHT/2)-bottomBounds.y ; + this.offsetLayout_(layoutItem.bottomChildren, dyBottom) + bottomBounds.offset(0, dyBottom); + bounds.accumulate(bottomBounds); + + lp.cx = Math.max(lp.cx, topCx) + CELL_WIDTH; + lp.cy = y0; + + layoutItem.bounds.width = lp.cx - layoutItem.bounds.x; + bounds.accumulate(layoutItem.bounds); + + if (layoutItem.topChildren.length === 0) { + layoutItem.topConnectorY = bounds.y + CELL_HEIGHT / 2; + } else { + layoutItem.topConnectorY = layoutItem.topChildren[0].bounds.y + CELL_HEIGHT / 2; + } + if (layoutItem.bottomChildren.length === 0) { + layoutItem.bottomConnectorY = bounds.y + bounds.height - CELL_HEIGHT / 2; + } else { + layoutItem.bottomConnectorY = layoutItem.bottomChildren[0].bounds.y + CELL_HEIGHT / 2; + } + } else { + layoutItem.bounds.x = lp.cx; + layoutItem.bounds.y = lp.cy; + lp.cx += CELL_WIDTH; + layoutItem.bounds.width = CELL_WIDTH; + layoutItem.bounds.height = CELL_HEIGHT; + bounds.accumulate(layoutItem.bounds); + + } + } + return bounds; + } + doLayout(layoutItems: PedalLayout[]): LayoutSize { + const TWO_ROW_HEIGHT = 142 - 14; + + if (layoutItems.length === 0) + { + // if the current pedalboard is empty, reserve display space anyway. + return {width: 1, height: TWO_ROW_HEIGHT}; + } + + let lp = new LayoutParams(); + + let bounds = this.doLayout2_(lp, layoutItems); + // shift everything down so there are no negative y coordinates. + + if (bounds.height < TWO_ROW_HEIGHT) { + + let extra = Math.floor((TWO_ROW_HEIGHT - Math.ceil(bounds.height))/2); + this.offsetLayout_(layoutItems, Math.floor(-bounds.y + extra )); + bounds.height += extra; + + } else { + this.offsetLayout_(layoutItems, -bounds.y); + } + + bounds.height += 14; // for labels that aren't accounted for. + return { width: bounds.width, height: bounds.height }; + + } + + onItemClick(e: SyntheticEvent, instanceId?: number): void { + if (instanceId) { + this.setSelection(instanceId); + } + } + setSelection(instanceId: number) { + if (this.props.onSelectionChanged) { + this.props.onSelectionChanged(instanceId); + } + } + + isTouchDevice(): boolean { + return (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)); + } + + onItemDoubleClick(event: SyntheticEvent, instanceId?: number): void { + event.preventDefault(); + event.stopPropagation(); + + if (this.props.onDoubleClick && instanceId) { + this.props.onDoubleClick(instanceId); + } + + } + + onItemLongClick(event: SyntheticEvent, instanceId?: number): void { + event.preventDefault(); + event.stopPropagation(); + + if (!this.isTouchDevice()) { + if (this.props.onDoubleClick && instanceId) { + this.props.onDoubleClick(instanceId); + } + } + + } + + + renderConnector(output: ReactNode[], item: PedalLayout, enabled: boolean): void { + // let classes = this.props.classes; + let x_ = item.bounds.x + CELL_WIDTH / 2; + let y_ = item.bounds.y + CELL_HEIGHT / 2; + let isStereo = item.stereoOutput; + let color = enabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR; + let svgPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_ + CELL_WIDTH, y_).toString(); + + if (isStereo) { + output.push(( + + )); + output.push(( + + )); + } else { + output.push(( + + )); + } + } + renderSplitConnectors(output: ReactNode[], item: PedalLayout, enabled: boolean, shortSplitOutput: boolean,): void { + //let classes = this.props.classes; + let x_ = item.bounds.x + CELL_WIDTH / 2; + let y_ = item.bounds.y + CELL_HEIGHT / 2; + let yTop = item.topConnectorY; + let yBottom = item.bottomConnectorY; + //let isStereo = item.stereoOutput; + let split = item.pedalItem as PedalBoardSplitItem; + + let topEnabled = enabled && split.isASelected(); + let bottomEnabled = enabled && split.isBSelected(); + let topColor = topEnabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR; + let bottomColor = bottomEnabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR; + + + let topStartPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_, yTop).lineTo(x_ + CELL_WIDTH, yTop).toString(); + let bottomStartPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_, yBottom).lineTo(x_ + CELL_WIDTH, yBottom).toString(); + + if (item.stereoInput && item.topChildren[0].stereoInput) { + output.push(()); + output.push(()); + } else { + output.push(()); + } + + if (item.stereoInput && item.bottomChildren[0].stereoInput) { + output.push(()); + output.push(()); + + } else { + output.push(()); + } + + let lastTop = item.topChildren[item.topChildren.length - 1]; + let lastBottom = item.bottomChildren[item.bottomChildren.length - 1]; + + let xTop = lastTop.bounds.right - CELL_WIDTH / 2; + let xBottom = lastBottom.bounds.right - CELL_WIDTH / 2; + + let xEnd = shortSplitOutput ? item.bounds.right : item.bounds.right + CELL_WIDTH / 2; + let xTee0 = item.bounds.right - CELL_WIDTH / 2; + + let firstPath: string; + let secondPath: string; + + let firstPathStereo: boolean; + let secondPathStereo: boolean; + let firstPathEnabled: boolean; + let secondPathEnabled: boolean; + let xTee: number; + + let monoAdjustment = (STEREO_STROKE_WIDTH - STROKE_WIDTH) / 2; + + let bottomPathFirst = topEnabled && !bottomEnabled; + let topPathFirst = bottomEnabled && !topEnabled; + + if (bottomPathFirst || (topEnabled && lastTop.stereoOutput)) { + // draw the bottom path first. + firstPathStereo = item.stereoOutput && lastBottom.stereoOutput; + secondPathStereo = item.stereoOutput && lastTop.stereoOutput; + xTee = firstPathStereo ? xTee0 : xTee0 - monoAdjustment; + firstPath = new SvgPathBuilder().moveTo(xBottom, yBottom).lineTo(xTee, yBottom).lineTo(xTee, y_).toString(); + xTee = secondPathStereo ? xTee0 : xTee0 - monoAdjustment; + + secondPath = new SvgPathBuilder().moveTo(xTop, yTop).lineTo(xTee, yTop).lineTo(xTee, y_).lineTo(xEnd, y_).toString(); + firstPathEnabled = bottomEnabled; + secondPathEnabled = topEnabled; + } else { + // draw the top path first. + firstPathStereo = item.stereoOutput && lastTop.stereoOutput; + secondPathStereo = item.stereoOutput && lastBottom.stereoOutput; + + xTee = firstPathStereo ? xTee0 : xTee0 - monoAdjustment; + firstPath = new SvgPathBuilder().moveTo(xTop, yTop).lineTo(xTee, yTop).lineTo(xTee, y_).toString(); + + xTee = secondPathStereo ? xTee0 : xTee0 - monoAdjustment; + secondPath = new SvgPathBuilder().moveTo(xBottom, yBottom).lineTo(xTee, yBottom).lineTo(xTee, y_).lineTo(xEnd, y_).toString(); + + firstPathEnabled = topEnabled; + secondPathEnabled = bottomEnabled; + } + let firstPathColor = firstPathEnabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR; + let secondPathColor = secondPathEnabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR; + + if (bottomPathFirst || topPathFirst) { + // display stereo strokes with cutoff line. + if (firstPathStereo) { + output.push(( + + )); + output.push(( + + )); + } else { + output.push(( + + )); + } + if (secondPathStereo) { + output.push(( + + )); + output.push(( + + )); + } else { + output.push(( + + )); + } + + } else { + // stereo strokes merge. + if (firstPathStereo) { + output.push(( + + )); + } else { + output.push(( + + )); + } + if (secondPathStereo) { + output.push(( + + )); + } else { + output.push(( + + )); + } + + // draw stereo inner lines. + if (firstPathStereo) { + output.push(( + + )); + } + if (secondPathStereo) { + output.push(( + + )); + + } + } + } + getScrollContainer() + { + let el: HTMLElement | undefined | null= this.scrollRef.current; + // actually not here anymore. :-/ It has a reactive definition in MainPage.tsx now. + while (el) + { + if (el.id === "pedalBoardScroll") + { + return el as HTMLDivElement; + } + el = el.parentElement; + } + throw new PiPedalStateError("scroll container not found."); + } + + pedalButton(instanceId: number, iconUrl: string, draggable: boolean, enabled: boolean): ReactNode { + let classes = this.props.classes; + return ( +
{ e.preventDefault(); }}> + + { this.onItemClick(e, instanceId); }} + onDoubleClick={(e: SyntheticEvent) => { this.onItemDoubleClick(e, instanceId); }} + onContextMenu={(e: SyntheticEvent) => { this.onItemLongClick(e, instanceId); }} + > + + this.getScrollContainer()} + onDragEnd={(x, y) => { this.onDragEnd(instanceId, x, y) }} + > +
+ Pedal +
+
+
+
+ ); + + } + renderConnectors(output: ReactNode[], layoutChain: PedalLayout[], enabled: boolean, shortSplitOutput: boolean): void { + let length = layoutChain.length - 1; + if (layoutChain.length > 0 && layoutChain[layoutChain.length - 1].isSplitter()) { + ++length; + } + for (let i = 0; i < length; ++i) { + let item = layoutChain[i]; + if (item.isSplitter()) { + let splitter = item.pedalItem as PedalBoardSplitItem; + this.renderSplitConnectors(output, item, enabled, i === length - 1 && shortSplitOutput,); + this.renderConnectors(output, item.topChildren, enabled && splitter.isASelected(), false); + this.renderConnectors(output, item.bottomChildren, enabled && splitter.isBSelected(), false); + + } else if (item.uri !== END_PEDALBOARD_ITEM_URI) { + this.renderConnector(output, item, enabled); + + } + } + } + renderConnectorFrame(layoutChain: PedalLayout[], layoutSize: LayoutSize): ReactNode { + let output: ReactNode[] = []; + this.renderConnectors(output, layoutChain, true, false); + + return ( + + + { + output + } + + + + ); + + } + + renderChain(layoutChain: PedalLayout[], layoutSize: LayoutSize): ReactNode { + + let classes = this.props.classes; + + let result: ReactNode[] = []; + + result.push(this.renderConnectorFrame(layoutChain, layoutSize)); + + let it = chainIterator(layoutChain); + while (true) { + let v = it.next(); + if (v.done) break; + let item = v.value; + switch (item.uri) { + case START_PEDALBOARD_ITEM_URI: + result.push(
+ +
); + break; + case END_PEDALBOARD_ITEM_URI: + result.push(
+ +
); + break; + default: + if (item.isSplitter()) { + + result.push(
+
+ {this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), false,true)} +
+
); + + } else { + result.push( +
+ {item.pedalItem?.pluginName} +
+ ) + result.push(
+ {this.pedalButton(item.pedalItem?.instanceId ?? -1, item.iconUrl, !item.isEmpty(), item.pedalItem?.isEnabled ?? false)} + +
); + + } + break; + } + + } + return result; + } + + canInputStero(item: PedalLayout): boolean { + if (item.pedalItem) { + let plugin = this.model.getUiPlugin(item.pedalItem.uri); + if (plugin) { + return plugin.audio_inputs === 2; + } + } + return true; + } + canOutputStereo(item: PedalLayout): boolean { + if (item.pedalItem) { + let plugin = this.model.getUiPlugin(item.pedalItem.uri); + if (plugin) { + return plugin.audio_outputs === 2; + } + } + return true; + } + + markStereoOutputs(layoutChain: PedalLayout[], stereoInput: boolean, stereoOutput: boolean) { + // analyze forward flow. + this.markStereoForward(layoutChain, stereoInput); + // mark items that feed a mono effect as mono. + this.markStereoBackward(layoutChain, stereoOutput); + } + + markStereoBackward(layoutChain: PedalLayout[], stereoOutput: boolean) : boolean + { + for (let i = layoutChain.length-1; i >= 0; --i) + { + let item = layoutChain[i]; + if (item.isSplitter()) + { + if (!stereoOutput) + { + item.stereoOutput = false; + } + this.markStereoBackward(item.topChildren,stereoOutput); + this.markStereoBackward(item.bottomChildren,stereoOutput); + let topStereoInput = item.topChildren[0].stereoInput; + let bottomStereoInput = item.bottomChildren[0].stereoInput; + + if (! (topStereoInput || bottomStereoInput)) + { + let splitItem = item.pedalItem as PedalBoardSplitItem; + if (splitItem.getSplitType() !== SplitType.Lr) + { + item.stereoInput = false; + } + } + } else if (item.isEnd()) + { + + } else if (item.isStart()) + { + if (!stereoOutput) + { + item.stereoOutput = false; + } + return item.stereoOutput; + + } else if (item.isEmpty()) { + if (!stereoOutput) + { + item.stereoOutput = false; + item.stereoInput = false; + } + } else { + if (!stereoOutput) + { + item.stereoOutput = false; + } + } + stereoOutput = item.stereoInput; + } + return stereoOutput; + } + markStereoForward(layoutChain: PedalLayout[],stereoInput: boolean): boolean + { + if (layoutChain.length === 0) { + return stereoInput; + } + for (let i = 0; i < layoutChain.length; ++i) { + let item = layoutChain[i]; + if (item.isSplitter()) { + let splitter = item.pedalItem as PedalBoardSplitItem; + item.stereoInput = stereoInput; + + let isChainInputStereo = stereoInput; + if (splitter.getSplitType() === SplitType.Lr) + { + isChainInputStereo = false; + } + + let topStereo = this.markStereoForward(item.topChildren, isChainInputStereo); + let bottomStereo = this.markStereoForward(item.bottomChildren, isChainInputStereo); + + + if (splitter.getSplitType() === SplitType.Ab) { + if (splitter.isASelected()) { + item.stereoOutput = topStereo; + } else { + item.stereoOutput = bottomStereo; + } + } else { + item.stereoOutput = topStereo || bottomStereo; + } + } else if (item.isStart()) + { + item.stereoOutput = (PiPedalModelFactory.getInstance().jackSettings.get().inputAudioPorts.length > 1); + } else if (item.isEnd()) { + item.stereoInput = (PiPedalModelFactory.getInstance().jackSettings.get().outputAudioPorts.length > 1) && stereoInput; + return item.stereoInput; + } else if (item.isEmpty()) { + item.stereoInput = stereoInput; + item.stereoOutput = stereoInput; + } else { + if (stereoInput && this.canOutputStereo(item)) { + item.stereoInput = true; + } else { + item.stereoInput = false; + } + item.stereoOutput = this.canOutputStereo(item); + } + stereoInput = item.stereoOutput; + } + return stereoInput; + } + + currentLayout?: PedalLayout[]; + + render() { + const { classes } = this.props; + + let layoutChain = makeChain(this.model, this.state.pedalBoard?.items); + let start = PedalLayout.Start(); + let end = PedalLayout.End(); + if (layoutChain.length !== 0) + { + layoutChain.splice(0, 0, start); + layoutChain.splice(layoutChain.length, 0, end); + this.markStereoOutputs(layoutChain, true, true); + } + + let layoutSize = this.doLayout(layoutChain); + + + this.currentLayout = layoutChain; // save for mouse processing &c. + + return ( +
+
+ {this.renderChain(layoutChain, layoutSize)} +
+
+ ); + } + + } + ); + +export default PedalBoardView \ No newline at end of file diff --git a/react/src/PiPedalError.tsx b/react/src/PiPedalError.tsx new file mode 100644 index 0000000..ba43f8d --- /dev/null +++ b/react/src/PiPedalError.tsx @@ -0,0 +1,26 @@ + +export class PiPedalError extends Error { + constructor(message: string) + { + super(message); + this.name = "PiPedalError"; + } +} + +export class PiPedalArgumentError extends PiPedalError { + constructor(message: string) + { + super(message); + this.name = "PiPedalArgumentError"; + } +} +export class PiPedalStateError extends PiPedalError { + constructor(message: string) + { + super(message); + this.name = "PiPedalStateError"; + } +} + +export default PiPedalError; + diff --git a/react/src/PiPedalModel.tsx b/react/src/PiPedalModel.tsx new file mode 100644 index 0000000..51c0d2d --- /dev/null +++ b/react/src/PiPedalModel.tsx @@ -0,0 +1,1451 @@ +import { UiPlugin, UiControl, PluginType } from './Lv2Plugin'; + +import { PiPedalArgumentError, PiPedalStateError } from './PiPedalError'; + +import { ObservableProperty } from './ObservableProperty'; +import { PedalBoard, ControlValue } from './PedalBoard' +import PluginClass from './PluginClass'; +import PiPedalSocket, { PiPedalMessageHeader } from './PiPedalSocket'; +import { nullCast } from './Utility' +import { JackConfiguration, JackChannelSelection } from './Jack'; +import { BankIndex } from './Banks'; +import JackHostStatus from './JackHostStatus'; +import JackServerSettings from './JackServerSettings'; +import MidiBinding from './MidiBinding'; +import PluginPreset from './PluginPreset'; + + +export enum State { + Loading, + Ready, + Error, + Reconnecting +}; + + +export interface VuUpdateInfo { + instanceId: number; + + sampleTime: number; // in samples. + isStereoInput: boolean; + isStereoOutput: boolean; + inputMaxValueL: number; + inputMaxValueR: number; + outputMaxValueL: number; + outputMaxValueR: number; +}; + +export interface MonitorPortHandle { + +}; + +class MidiEventListener { + constructor(handle: number, callback: (isNote: boolean, noteOrControl: number) => void) { + this.handle = handle; + this.callback = callback; + } + handle: number; + callback: (isNote: boolean, noteOrControl: number) => void; +}; + +export interface ListenHandle { + _handle: number; +} +class MonitorPortHandleImpl implements MonitorPortHandle { + constructor(instanceId: number, key: string, onUpdated: (value: number) => void) { + this.instanceId = instanceId; + this.key = key; + this.onUpdated = onUpdated; + } + valid: boolean = true; + subscriptionHandle?: number; + + instanceId: number; + key: string; + onUpdated: (value: number) => void + +}; + +export interface VuSubscriptionHandle { + +}; + +class VuSubscriptionHandleImpl implements VuSubscriptionHandle { + constructor(instanceId_: number, callback_: VuChangedHandler) { + this.instanceId = instanceId_; + this.callback = callback_; + } + instanceId: number; + callback: VuChangedHandler; +}; + +export type VuChangedHandler = (vuInfo: VuUpdateInfo) => void; + + +class VuSubscriptionTarget { + serverSubscriptionHandle?: number; + subscribers: VuSubscriptionHandleImpl[] = []; +}; + +export type PiPedalVersion = { + server: string; + serverVersion: string; + operatingSystem: string; + osVersion: string; + debug: boolean; +}; + +export class PresetIndexEntry { + deserialize(input: any): PresetIndexEntry { + this.instanceId = input.instanceId; + this.name = input.name; + return this; + } + static deserialize_array(input: any): PresetIndexEntry[] { + let result: PresetIndexEntry[] = []; + for (let i = 0; i < input.length; ++i) { + result[i] = new PresetIndexEntry().deserialize(input[i]); + } + return result; + } + instanceId: number = 0; + name: string = ""; + + areEqual(other: PresetIndexEntry): boolean { + return ( + (this.instanceId === other.instanceId) + && this.name === other.name + ); + } +}; + +export class PresetIndex { + deserialize(input: any): PresetIndex { + this.selectedInstanceId = input.selectedInstanceId; + this.presetChanged = input.presetChanged; + this.presets = PresetIndexEntry.deserialize_array(input.presets); + return this; + } + selectedInstanceId: number = 0; + presetChanged: boolean = false; + presets: PresetIndexEntry[] = []; + + clone(): PresetIndex { + return new PresetIndex().deserialize(this); + } + areEqual(other: PresetIndex, includeSelectedInstance: boolean): boolean { + if (includeSelectedInstance && this.selectedInstanceId !== other.selectedInstanceId) return false; + if (this.presets.length !== other.presets.length) return false; + for (let i = 0; i < this.presets.length; ++i) { + if (!this.presets[i].areEqual(other.presets[i])) return false; + } + return true; + } + getItem(instanceId: number): PresetIndexEntry | null { + for (let i = 0; i < this.presets.length; ++i) { + if (this.presets[i].instanceId === instanceId) { + return this.presets[i]; + } + } + return null; + } + getSelectedText(): string { + let item = this.getItem(this.selectedInstanceId); + if (item === null) return ""; + + if (this.presetChanged) { + return item.name + " *"; + } else { + return item.name; + } + } + addItem(instanceId: number, name: string): number { + let newItem: PresetIndexEntry = new PresetIndexEntry(); + newItem.instanceId = instanceId; + newItem.name = name; + this.presets.push(newItem); + return newItem.instanceId; + } + movePreset(from: number, to: number) { + let newElements = this.presets; + let t = newElements[from]; + newElements.splice(from, 1); + newElements.splice(to, 0, t); + + } + deleteItem(instanceId: number): number { + for (let i = 0; i < this.presets.length; ++i) { + let preset = this.presets[i]; + if (preset.instanceId === instanceId) { + this.presets.splice(i, 1); + if (i < this.presets.length) { + return this.presets[i].instanceId; + } else { + if (i - 1 > 0) { + return this.presets[i - 1].instanceId; + } else { + return -1; + } + } + } + } + return -1; + + } + + +} + +interface MonitorPortOutputBody { + subscriptionHandle: number; + value: number; +} + + +interface ChannelSelectionChangedBody { + clientId: number; + jackChannelSelection: JackChannelSelection; +} +interface RenamePresetBody { + clientId: number; + instanceId: number; + name: string; +} + +interface PresetsChangedBody { + clientId: number, + presets: PresetIndex +} +interface PedalBoardItemEnableBody { + clientId: number, + instanceId: number, + enabled: boolean +} +interface PedalBoardChangedBody { + clientId: number; + pedalBoard: PedalBoard; +} +interface ControlChangedBody { + clientId: number; + instanceId: number; + symbol: string; + value: number; +}; + + +export interface PiPedalModel { + clientId: number; + serverVersion?: PiPedalVersion; + errorMessage: ObservableProperty; + alertMessage: ObservableProperty; + state: ObservableProperty; + ui_plugins: ObservableProperty; + plugin_classes: ObservableProperty; + jackConfiguration: ObservableProperty; + jackSettings: ObservableProperty; + banks: ObservableProperty; + jackServerSettings: ObservableProperty; + + presets: ObservableProperty; + + setJackServerSettings(jackServerSettings: JackServerSettings): void; + setMidiBinding(instanceId: number, midiBinding: MidiBinding): void; + + + getUiPlugin(uri: string): UiPlugin | null; + + pedalBoard: ObservableProperty; + loadPedalBoardPlugin(itemId: number, selectedUri: string): number; + + setPedalBoardControlValue(instanceId: number, key: string, value: number): void; + setPedalBoardItemEnabled(instanceId: number, value: boolean): void; + previewPedalBoardValue(instanceId: number, key: string, value: number): void; + setPedalBoardControlValue(instanceId: number, key: string, value: number): void; + deletePedalBoardPedal(instanceId: number): number | null; + + movePedalBoardItem(fromInstanceId: number, toInstanceId: number): void; + movePedalBoardItemToStart(fromInstanceId: number): void; + movePedalBoardItemToEnd(fromInstanceId: number): void; + movePedalBoardItemBefore(fromInstanceId: number, toInstanceId: number): void; + movePedalBoardItemAfter(fromInstanceId: number, toInstanceId: number): void; + + addPedalBoardItem(instanceId: number, append: boolean): number; + addPedalBoardSplitItem(instanceId: number, append: boolean): number; + setPedalBoardItemEmpty(instanceId: number): number; + + saveCurrentPreset(): void; + saveCurrentPresetAs(newName: string): void; + + loadPreset(instanceId: number): void; + updatePresets(presets: PresetIndex): Promise; + deletePresetItem(instanceId: number): Promise; + renamePresetItem(instanceId: number, name: string): Promise; + copyPreset(fromId: number, toId: number): Promise; + duplicatePreset(instanceId: number): Promise; + + moveBank(from: number, to: number): Promise; + deleteBankItem(instanceId: number): Promise; + + + showAlert(message: string): void; + + setJackSettings(jackSettings: JackChannelSelection): void; + + svgImgUrl(svgImage: string): string; + + removeVuSubscription(handle: VuSubscriptionHandle): void; + addVuSubscription(instanceId: number, vuChangedHandler: VuChangedHandler): VuSubscriptionHandle; + + monitorPort(instanceid: number, key: string, updateRateSeconds: number, onUpdated: (value: number) => void): MonitorPortHandle; + unmonitorPort(handle: MonitorPortHandle): void; + + getLv2Parameter(instanceId: number, uri: string): Promise; + + renameBank(instanceId: number, newName: string): Promise; + saveBankAs(instanceId: number, newName: string): Promise; + openBank(bankId: number): Promise; + + getJackStatus(): Promise; + + getPluginPresets(uri: string): Promise; + loadPluginPreset(instanceId: number, presetName: string): void; + + shutdown(): Promise; + restart(): Promise; + + listenForMidiEvent(listenForControlsOnly: boolean, onComplete: (isNote: boolean, noteOrControl: number) => void): ListenHandle; + cancelListenForMidiEvent(listenHandle: ListenHandle): void; + + download(targetType: string, isntanceId: number): void; + + uploadPreset(file: File, uploadAfter: number): Promise; + +}; + +class PiPedalModelImpl implements PiPedalModel { + clientId: number = -1; + + serverVersion?: PiPedalVersion; + + socketServerUrl: string = ""; + varServerUrl: string = ""; + lv2Path: string = ""; + webSocket?: PiPedalSocket; + + ui_plugins: ObservableProperty + = new ObservableProperty([]); + state: ObservableProperty = new ObservableProperty(State.Loading); + errorMessage: ObservableProperty = new ObservableProperty(""); + alertMessage: ObservableProperty = new ObservableProperty(""); + pedalBoard: ObservableProperty = new ObservableProperty(new PedalBoard()); + plugin_classes: ObservableProperty = new ObservableProperty(new PluginClass()); + jackConfiguration: ObservableProperty = new ObservableProperty(new JackConfiguration()); + jackSettings: ObservableProperty = new ObservableProperty(new JackChannelSelection()); + banks: ObservableProperty + = new ObservableProperty(new BankIndex()); + jackServerSettings: ObservableProperty + = new ObservableProperty(new JackServerSettings()); + + + presets: ObservableProperty = new ObservableProperty + ( + new PresetIndex() + ); + + + svgImgUrl(svgImage: string): string { + //return this.varServerUrl + "img/" + svgImage; + return "img/" + svgImage; + } + + + getUiPlugin(uri: string): UiPlugin | null { + let plugins: UiPlugin[] = this.ui_plugins.get(); + + for (let plugin of plugins) { + if (plugin.uri === uri) return plugin; + } + return null; + } + + + constructor() { + this.onSocketError = this.onSocketError.bind(this); + this.onSocketMessage = this.onSocketMessage.bind(this); + this.onSocketReconnecting = this.onSocketReconnecting.bind(this); + this.onSocketReconnected = this.onSocketReconnected.bind(this); + } + onSocketReconnecting(retry: number, maxRetries: number): void { + if (retry !== 0) { + this.setState(State.Reconnecting); + } + } + + + onSocketError(errorMessage: string, exception: any) { + this.onError(errorMessage); + } + onSocketMessage(header: PiPedalMessageHeader, body?: any) { + let message = header.message; + if (message === "onMonitorPortOutput") { + let monitorPortOutputBody = body as MonitorPortOutputBody; + for (let i = 0; i < this.monitorPortSubscriptions.length; ++i) { + let subscription = this.monitorPortSubscriptions[i]; + if (subscription.subscriptionHandle === monitorPortOutputBody.subscriptionHandle) { + subscription.onUpdated(body.value); + break; + } + } + if (header.replyTo) { + this.webSocket?.reply(header.replyTo, "onMonitorPortOutput", true); + } + + } else if (message === "onChannelSelectionChanged") { + let channelSelectionBody = body as ChannelSelectionChangedBody; + let channelSelection = new JackChannelSelection().deserialize(channelSelectionBody.jackChannelSelection); + this.jackSettings.set(channelSelection); + } else if (message === "onPresetsChanged") { + let presetsChangedBody = body as PresetsChangedBody; + let presets = new PresetIndex().deserialize(presetsChangedBody.presets); + this.presets.set(presets); + } else if (message === "onJackConfigurationChanged") { + this.jackConfiguration.set(new JackConfiguration().deserialize(body)); + } else if (message === "onLoadPluginPreset") { + let instanceId = body.instanceId as number; + let controlValues = ControlValue.deserializeArray(body.controlValues); + this.handleOnLoadPluginPreset(instanceId, controlValues); + } else if (message === "onItemEnabledChanged") { + let itemEnabledBody = body as PedalBoardItemEnableBody; + this._setPedalBoardItemEnabled( + itemEnabledBody.instanceId, + itemEnabledBody.enabled, + false // No server notification. + ); + } else if (message === "onPedalBoardChanged") { + let pedalChangedBody = body as PedalBoardChangedBody; + // xxx: do we want to optimize for messages we went ourselves?? + // we could actually protect against preview collisions in the model. + this.pedalBoard.set(new PedalBoard().deserialize(pedalChangedBody.pedalBoard)); + + } else if (message === "onMidiValueChanged") { + let controlChangedBody = body as ControlChangedBody; + // xxx: do we want to optimize for messages we went ourselves?? + // we could actually protect against preview collisions in the model. + this._setPedalBoardControlValue( + controlChangedBody.instanceId, + controlChangedBody.symbol, + controlChangedBody.value, + false // do NOT notify the server of the change. + ); + if (header.replyTo) { + this.webSocket?.reply(header.replyTo, "onMidiValueChanged", true); + } + + } else if (message === "onNotifyMidiListener") { + let clientHandle = body.clientHandle as number; + let isNote = body.isNote as boolean; + let noteOrControl = body.noteOrControl as number; + this.handleNotifyMidiListener(clientHandle, isNote, noteOrControl); + } else if (message === "onControlChanged") { + let controlChangedBody = body as ControlChangedBody; + // xxx: do we want to optimize for messages we went ourselves?? + // we could actually protect against preview collisions in the model. + this._setPedalBoardControlValue( + controlChangedBody.instanceId, + controlChangedBody.symbol, + controlChangedBody.value, + false // do NOT notify the server of the change. + ); + } else if (message === "onJackServerSettingsChanged") { + let jackServerSettings = new JackServerSettings().deserialize(body); + this.jackServerSettings.set(jackServerSettings); + } else if (message === "onBanksChanged") { + let banks = new BankIndex().deserialize(body); + this.banks.set(banks); + } else if (message === "onVuUpdate") { + let vuUpdate = body as VuUpdateInfo; + let item = this.vuSubscriptions[vuUpdate.instanceId]; + if (item) { + for (let i = 0; i < item.subscribers.length; ++i) { + item.subscribers[i].callback(vuUpdate); + } + } + if (header.replyTo) { + this.webSocket?.reply(header.replyTo, "onVuUpdate", true); + } + + } else { + throw new PiPedalStateError("Unrecognized message received from server."); + } + } + setError(message: string): void { + this.errorMessage.set(message); + this.setState(State.Error); + } + varRequest(url: string): string { + return "var/" + url; + } + + setState(state: State) { + if (this.state.get() !== state) { + this.state.set(state); + } + } + + validatePlugins(plugin: PluginClass) { + if (plugin.plugin_type === PluginType.None) { + console.log("Error: No plugin type for uri '" + plugin.uri + "'"); + } + for (let i = 0; i < plugin.children.length; ++i) { + this.validatePlugins(plugin.children[i]); + } + } + + requestPluginClasses(): Promise { + const myRequest = new Request(this.varRequest('plugin_classes.json')); + return fetch(myRequest) + .then( + response => response.json() + ) + .then(data => { + let plugins = new PluginClass().deserialize(data); + + this.validatePlugins(plugins); + this.plugin_classes.set(plugins); + return true; + }) + .catch((error) => { + this.setError("Can't contact server.\n\n" + error); + return false; + }); + + } + getWebSocket(): PiPedalSocket { + if (this.webSocket === undefined) { + throw new PiPedalStateError("Attempt to access web socket before it's connected."); + } + return this.webSocket; + } + + onSocketReconnected() { + // reload state, but not configuration. + this.getWebSocket().request("hello") + .then(clientId => { + this.clientId = clientId; + return this.getWebSocket().request("currentPedalBoard"); + }) + .then(data => { + this.pedalBoard.set(new PedalBoard().deserialize(data)); + + return this.getWebSocket().request("getJackServerSettings"); + }) + .then(data => { + this.jackServerSettings.set(new JackServerSettings().deserialize(data)); + + return this.getWebSocket().request("getPresets"); + }) + .then((data) => { + this.presets.set(new PresetIndex().deserialize(data)); + + return this.getWebSocket().request("getJackConfiguration"); + }) + .then((data) => { + // data.isValid = false; + // data.errorState = "Jack Audio server not running." + + this.jackConfiguration.set(new JackConfiguration().deserialize(data)); + + return this.getWebSocket().request("getJackSettings"); + }) + .then((data) => { + this.jackSettings.set(new JackChannelSelection().deserialize(data)); + + return this.getWebSocket().request("getBankIndex"); + }) + .then((data) => { + this.banks.set(new BankIndex().deserialize(data)); + + + this.setState(State.Ready); + }) + .catch((what) => { + this.onError(what); + }) + } + makeSocketServerUrl(hostName: string, port: number): string { + return "ws://" + hostName + ":" + port + "/piddle"; + + } + makeVarServerUrl(protocol: string, hostName: string, port: number): string { + return protocol + "://" + hostName + ":" + port + "/var/"; + + } + + maxUploadSize: number = 512*1024; + + requestConfig(): Promise { + const myRequest = new Request(this.varRequest('config.json')); + return fetch(myRequest) + .then( + response => response.json() + + ) + .then(data => { + console.log("Got config"); + if (data.max_upload_size) + { + this.maxUploadSize = data.max_upload_size; + } + let { socket_server_port, socket_server_address } = data; + if ((!socket_server_address) || socket_server_address === "*") { + socket_server_address = window.location.hostname; + } + if (!socket_server_port) socket_server_port = 8080; + let socket_server = this.makeSocketServerUrl(socket_server_address, socket_server_port); + let var_server_url = this.makeVarServerUrl("http", socket_server_address, socket_server_port); + + + this.socketServerUrl = socket_server; + this.varServerUrl = var_server_url; + + this.webSocket = new PiPedalSocket( + this.socketServerUrl, + this.onSocketMessage, + this.onSocketError, + this.onSocketReconnecting, + this.onSocketReconnected); + return this.webSocket.connect(); + }) + .then(() => { + return this.getWebSocket().request("hello"); + }) + .then((clientId) => { + this.clientId = clientId; + return true; + }) + .catch((error) => { + this.setError("Failed to connect to server. " + error); + return false; + }) + .then((succeeded) => { + if (!succeeded) return false; + return this.getWebSocket().request("version").then(data => { + this.serverVersion = data; + return this.getWebSocket().request("plugins"); + }) + .then(data => { + this.ui_plugins.set(UiPlugin.deserialize_array(data)); + + return this.getWebSocket().request("currentPedalBoard"); + }) + .then(data => { + this.pedalBoard.set(new PedalBoard().deserialize(data)); + + return this.getWebSocket().request("pluginClasses"); + }) + .then((data) => { + + this.plugin_classes.set(new PluginClass().deserialize(data)); + this.validatePlugins(this.plugin_classes.get()); + + return this.getWebSocket().request("getPresets"); + }) + .then((data) => { + this.presets.set(new PresetIndex().deserialize(data)); + + return this.getWebSocket().request("getJackServerSettings"); + }) + .then(data => { + this.jackServerSettings.set(new JackServerSettings().deserialize(data)); + + return this.getWebSocket().request("getJackConfiguration"); + }) + .then((data) => { + // data.isValid = false; + // data.errorState = "Jack Audio server not running." + + this.jackConfiguration.set(new JackConfiguration().deserialize(data)); + + return this.getWebSocket().request("getJackSettings"); + }) + .then((data) => { + this.jackSettings.set(new JackChannelSelection().deserialize(data)); + + return this.getWebSocket().request("getBankIndex"); + }) + .then((data) => { + this.banks.set(new BankIndex().deserialize(data)); + + return true; + }) + .catch((error) => { + this.setError("Failed to fetch server state.\n\n" + error); + return false; + }); + + }) + ; + } + + // requestPlugins(): Promise { + // const myRequest = new Request(this.varRequest('uiplugins.json')); + // return fetch(myRequest) + // .then( + // response => response.json() + // ) + // .then(data => { + // let plugins = UiPlugin.deserialize_array(data); + // this.ui_plugins.set(plugins); + // return true; + // }) + // .catch((error) => { + // this.setError("Can't contact server.\n\n" + error); + // return false; + // }); + + // } + requestCurrentPedalBoard(): Promise { + const myRequest = new Request(this.varRequest('current_pedalboard.json')); + return fetch(myRequest) + .then( + (response) => { + return response.json(); + } + ) + .then(data => { + let pedalBoard = new PedalBoard().deserialize(data); + pedalBoard.ensurePedalboardIds(); + this.pedalBoard.set(pedalBoard); + }); + } + + onError(msg: string): void { + this.errorMessage.set(msg); + this.state.set(State.Error); + + } + initialize(): void { + this.setError(""); + this.setState(State.Loading); + this.requestConfig() + .then((succeeded) => { + if (succeeded) { + this.state.set(State.Ready); + } + }) + .catch((error) => { + this.setError("Failed to get server state. \n\n" + error); + }); + } + + getControl(uiPlugin: UiPlugin, portSymbol: string): UiControl | null { + for (let i = 0; i < uiPlugin.controls.length; ++i) { + let control = uiPlugin.controls[i]; + if (control.symbol === portSymbol) { + return control; + } + + } + return null; + } + getDefaultValues(uri: string): ControlValue[] { + let uiPlugin = this.getUiPlugin(uri); + if (uiPlugin === null) throw new PiPedalArgumentError("Pedal uri not found."); + let result: ControlValue[] = []; + + let controls = uiPlugin.controls; + for (let i = 0; i < controls.length; ++i) { + let control = controls[i]; + + let uiControl = this.getControl(uiPlugin, control.symbol); + if (uiControl === null) { + // this is default values, so a mis-match is in fact a problem. + throw new PiPedalStateError("ui and pedealboard ports don't match."); + } + let cv = new ControlValue(); + cv.key = control.symbol; + cv.value = control.default_value; + + + result.push(cv); + } + return result; + + + } + + + + handleOnLoadPluginPreset(instanceId: number, controlValues: ControlValue[]) { + let pedalBoard = this.pedalBoard.get(); + if (pedalBoard === undefined) throw new PiPedalStateError("Pedalboard not ready."); + let newPedalBoard = pedalBoard.clone(); + + let item = newPedalBoard.getItem(instanceId); + + let changed = false; + for (let i = 0; i < controlValues.length; ++i) { + let controlValue = controlValues[i]; + changed = item.setControlValue(controlValue.key, controlValue.value) || changed; + } + if (changed) { + this.pedalBoard.set(newPedalBoard); + } + } + + + + _setPedalBoardControlValue(instanceId: number, key: string, value: number, notifyServer: boolean): void { + let pedalBoard = this.pedalBoard.get(); + if (pedalBoard === undefined) throw new PiPedalStateError("Pedalboard not ready."); + let newPedalBoard = pedalBoard.clone(); + + let item = newPedalBoard.getItem(instanceId); + let changed = item.setControlValue(key, value); + if (changed) { + this.pedalBoard.set(newPedalBoard); + if (notifyServer) { + this._setServerControl("setControl", instanceId, key, value); + } + } + + } + setPedalBoardControlValue(instanceId: number, key: string, value: number): void { + this._setPedalBoardControlValue(instanceId, key, value, true); + } + setPedalBoardItemEnabled(instanceId: number, value: boolean): void { + this._setPedalBoardItemEnabled(instanceId, value, true); + } + _setPedalBoardItemEnabled(instanceId: number, value: boolean, notifyServer: boolean): void { + let pedalBoard = this.pedalBoard.get(); + if (pedalBoard === undefined) throw new PiPedalStateError("Pedalboard not ready."); + let newPedalBoard = pedalBoard.clone(); + + let item = newPedalBoard.getItem(instanceId); + let changed = value !== item.isEnabled; + if (changed) { + item.isEnabled = value; + this.pedalBoard.set(newPedalBoard); + if (notifyServer) { + let body: PedalBoardItemEnableBody = { + clientId: this.clientId, + instanceId: instanceId, + enabled: value + } + this.webSocket?.send("setPedalBoardItemEnable", body); + + } + } + + } + + updateServerPedalBoard(): void { + let body: PedalBoardChangedBody = { + clientId: this.clientId, + pedalBoard: this.pedalBoard.get() + }; + this.webSocket?.send("setCurrentPedalBoard", body); + + } + + loadPedalBoardPlugin(itemId: number, selectedUri: string): number { + let pedalBoard = this.pedalBoard.get(); + if (pedalBoard === undefined) throw new PiPedalArgumentError("Can't clone an undefined object."); + let newPedalBoard = pedalBoard.clone(); + + let plugin = this.getUiPlugin(selectedUri); + if (plugin === null) { + throw new PiPedalArgumentError("Plugin not found."); + } + + let it = newPedalBoard.itemsGenerator(); + while (true) { + let v = it.next(); + if (v.done) break; + let item = v.value; + if (item.instanceId === itemId) { + item.instanceId = ++newPedalBoard.nextInstanceId; + item.uri = selectedUri; + item.pluginName = plugin.name; + item.controlValues = this.getDefaultValues(item.uri); + item.isEnabled = true; + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard() + return item.instanceId; + } + } + throw new PiPedalArgumentError("Pedalboard item not found."); + + } + _setServerControl(message: string, instanceId: number, key: string, value: number) { + let body: ControlChangedBody = { + clientId: this.clientId, + instanceId: instanceId, + symbol: key, + value: value + }; + this.webSocket?.send(message, body); + } + previewPedalBoardValue(instanceId: number, key: string, value: number): void { + // mouse is down. Don't update EVERYBODY, but we must change + // the control on the running audio plugin. + this._setServerControl("previewControl", instanceId, key, value); + } + + // returns the next selected instanceId, or null,if no item was deleted. + deletePedalBoardPedal(instanceId: number): number | null { + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let result = newPedalBoard.deleteItem(instanceId); + if (result != null) { + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + } + return result; + + + } + movePedalBoardItemBefore(fromInstanceId: number, toInstanceId: number): void { + if (fromInstanceId === toInstanceId) return; + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let fromItem = newPedalBoard.getItem(fromInstanceId); + if (fromItem === null) { + throw new PiPedalArgumentError("fromInstanceId not found."); + } + + newPedalBoard.deleteItem(fromInstanceId); + + newPedalBoard.addBefore(fromItem, toInstanceId); + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + + } + movePedalBoardItemAfter(fromInstanceId: number, toInstanceId: number): void { + if (fromInstanceId === toInstanceId) return; + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let fromItem = newPedalBoard.getItem(fromInstanceId); + if (fromItem === null) { + throw new PiPedalArgumentError("fromInstanceId not found."); + } + + newPedalBoard.deleteItem(fromInstanceId); + + newPedalBoard.addAfter(fromItem, toInstanceId); + + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + } + + movePedalBoardItemToStart(instanceId: number): void { + + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let fromItem = newPedalBoard.getItem(instanceId); + if (fromItem === null) { + throw new PiPedalArgumentError("fromInstanceId not found."); + } + + newPedalBoard.deleteItem(instanceId); + + newPedalBoard.addToStart(fromItem); + + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + } + movePedalBoardItemToEnd(instanceId: number): void { + + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let fromItem = newPedalBoard.getItem(instanceId); + if (fromItem === null) { + throw new PiPedalArgumentError("fromInstanceId not found."); + } + + newPedalBoard.deleteItem(instanceId); + + newPedalBoard.addToEnd(fromItem); + + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + + + } + + + movePedalBoardItem(fromInstanceId: number, toInstanceId: number): void { + if (fromInstanceId === toInstanceId) return; + + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let fromItem = newPedalBoard.getItem(fromInstanceId); + let toItem = newPedalBoard.getItem(toInstanceId); + if (fromItem === null) { + throw new PiPedalArgumentError("fromInstanceId not found."); + } + if (toItem === null) { + throw new PiPedalArgumentError("toInstanceId not found."); + } + let emptyItem = newPedalBoard.createEmptyItem(); + newPedalBoard.replaceItem(fromInstanceId, emptyItem); + newPedalBoard.replaceItem(toInstanceId, fromItem); + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + + } + addPedalBoardItem(instanceId: number, append: boolean): number { + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let item = newPedalBoard.getItem(instanceId); + if (item === null) { + throw new PiPedalArgumentError("instanceId not found."); + } + let newItem = newPedalBoard.createEmptyItem(); + newPedalBoard.addItem(newItem, instanceId, append); + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + return newItem.instanceId; + } + addPedalBoardSplitItem(instanceId: number, append: boolean): number { + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let item = newPedalBoard.getItem(instanceId); + if (item === null) { + throw new PiPedalArgumentError("instanceId not found."); + } + let newItem = newPedalBoard.createEmptySplit(); + newPedalBoard.addItem(newItem, instanceId, append); + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + return newItem.instanceId; + + } + setPedalBoardItemEmpty(instanceId: number): number { + let pedalBoard = this.pedalBoard.get(); + let newPedalBoard = pedalBoard.clone(); + let item = newPedalBoard.getItem(instanceId); + if (item === null) { + throw new PiPedalArgumentError("instanceId not found."); + } + newPedalBoard.setItemEmpty(item); + + this.pedalBoard.set(newPedalBoard); + this.updateServerPedalBoard(); + return item.instanceId; + + } + + + saveCurrentPreset(): void { + this.webSocket?.send("saveCurrentPreset", this.clientId); + } + + saveCurrentPresetAs(newName: string, saveAfterInstanceId = -1): Promise { + // default behaviour is to save after the currently selected preset. + if (saveAfterInstanceId === -1) { + saveAfterInstanceId = this.presets.get().selectedInstanceId; + } + let request: any = { + clientId: this.clientId, + name: newName, + saveAfterInstanceId: saveAfterInstanceId + + }; + + return nullCast(this.webSocket) + .request("saveCurrentPresetAs", request) + .then((data) => { + return data; + }); + } + + + loadPreset(instanceId: number): void { + this.webSocket?.send("loadPreset", instanceId); + + } + updatePresets(presets: PresetIndex): Promise { + return nullCast(this.webSocket).request("updatePresets", presets); + } + moveBank(from: number, to: number): Promise { + return nullCast(this.webSocket).request("moveBank", { from: from, to: to }); + } + + + deletePresetItem(instanceId: number): Promise { + return nullCast(this.webSocket).request("deletePresetItem", instanceId); + + } + deleteBankItem(instanceId: number): Promise { + return nullCast(this.webSocket).request("deleteBankItem", instanceId); + + } + + renamePresetItem(instanceId: number, name: string): Promise { + let body: RenamePresetBody = { + clientId: this.clientId, + instanceId: instanceId, + name: name + }; + + return nullCast(this.webSocket).request("renamePresetItem", body); + } + + copyPreset(fromId: number, toId: number = -1): Promise { + let body: any = { + clientId: this.clientId, + fromId: fromId, + toId: toId + }; + return nullCast(this.webSocket).request("copyPreset", body); + + } + duplicatePreset(instanceId: number): Promise { + return this.copyPreset(instanceId, -1); + } + + showAlert(message: string): void { + this.alertMessage.set(message); + } + setJackSettings(jackSettings: JackChannelSelection): void { + this.webSocket?.send("setJackSettings", jackSettings); + } + + + monitorPortSubscriptions: MonitorPortHandleImpl[] = []; + + monitorPort(instanceId: number, key: string, updateRateSeconds: number, onUpdated: (value: number) => void): MonitorPortHandle { + let result = new MonitorPortHandleImpl(instanceId, key, onUpdated); + this.monitorPortSubscriptions.push(result); + if (!this.webSocket) return result; + + + this.webSocket.request("monitorPort", + { + instanceId: instanceId, + key: key, + updateRate: updateRateSeconds + }) + .then((handle) => { + if (result.valid) { + result.subscriptionHandle = handle; + } else { + try { + this.webSocket?.send("unmonitorPort", handle); + } catch (err) { + + } + } + }); + return result; + + + } + unmonitorPort(handle: MonitorPortHandle): void { + let t = handle as MonitorPortHandleImpl; + + for (let i = 0; i < this.monitorPortSubscriptions.length; ++i) { + let item = this.monitorPortSubscriptions[i]; + if (item === t) { + this.monitorPortSubscriptions.splice(i, 1); + item.valid = false; + if (item.subscriptionHandle) { + try { + this.webSocket?.send("unmonitorPort", item.subscriptionHandle); + } catch (err) { + + } + } + break; + } + } + } + + vuSubscriptions: (VuSubscriptionTarget | undefined)[] = []; + + + addVuSubscription(instanceId: number, vuChangedHandler: VuChangedHandler): VuSubscriptionHandle { + + let result = new VuSubscriptionHandleImpl(instanceId, vuChangedHandler); + + if (!this.webSocket) return result; // racing to death. don't subscribe. + + let item = this.vuSubscriptions[instanceId]; + if (item) { + item.subscribers.push(result); + } else { + let newTarget = new VuSubscriptionTarget(); + newTarget.subscribers.push(result); + + this.webSocket.request("addVuSubscription", instanceId) + .then((subscriptionHandle) => { + newTarget.serverSubscriptionHandle = subscriptionHandle; + if (newTarget.subscribers.length === 0) { + this.webSocket?.send("removeVuSubscription", subscriptionHandle); + } else { + newTarget.serverSubscriptionHandle = subscriptionHandle; + } + }); + + this.vuSubscriptions[instanceId] = newTarget; + } + return result; + } + + removeVuSubscription(handle: VuSubscriptionHandle): void { + let handleImpl = handle as VuSubscriptionHandleImpl; + + let item = this.vuSubscriptions[handleImpl.instanceId]; + if (item) { + for (let i = 0; i < item.subscribers.length; ++i) { + if (item.subscribers[i] === handleImpl) { + item.subscribers.splice(i, 1); + if (item.subscribers.length === 0) { + this.vuSubscriptions[handleImpl.instanceId] = undefined; + if (item.serverSubscriptionHandle) { + this.webSocket?.send("removeVuSubscription", item.serverSubscriptionHandle); + item.serverSubscriptionHandle = undefined; + } + } + } + } + } + + } + + getLv2Parameter(instanceId: number, uri: string): Promise { + let result = new Promise((resolve, reject) => { + if (!this.webSocket) { + reject("Socket closed."); + } else { + this.webSocket.request("getLv2Parameter", { instanceId: instanceId, uri: uri }) + .then((data) => { + resolve(data); + }) + .catch(error => reject(error)); + } + }); + return result; + } + openBank(bankId: number): Promise { + let result = new Promise((resolve, reject) => { + if (this.webSocket) { + this.webSocket.request("openBank", bankId) + .then(() => { + resolve(); + + }) + .catch((error) => { + reject(error); + + }); + } + }); + return result; + } + renameBank(bankId: number, newName: string): Promise { + let result = new Promise((resolve, reject) => { + if (!this.webSocket) { + reject("No server connection."); + } else { + this.webSocket.request("renameBank", { bankId: bankId, newName: newName }) + .then(() => { + resolve(); + }) + .catch(error => reject(error)); + } + }); + return result; + } + saveBankAs(bankId: number, newName: string): Promise { + let result = new Promise((resolve, reject) => { + if (!this.webSocket) { + reject("No server connection."); + } else { + this.webSocket.request("saveBankAs", { bankId: bankId, newName: newName }) + .then((newInstanceId) => { + resolve(newInstanceId); + }) + .catch(error => reject(error)); + } + }); + return result; + } + + getJackStatus(): Promise { + let result = new Promise((resolve, reject) => { + if (!this.webSocket) { + reject("No connection to server."); + } else { + this.webSocket.request("getJackStatus") + .then((data) => { + resolve(new JackHostStatus().deserialize(data)); + }) + .catch(error => reject(error)); + } + }); + return result; + } + + presetCache: { [uri: string]: PluginPreset[]; } = {}; + + + getPluginPresets(uri: string): Promise { + return new Promise((resolve, reject) => { + if (this.presetCache[uri] !== undefined) { + resolve(this.presetCache[uri]); + } else { + this.webSocket!.request("getPluginPresets", uri) + .then((result) => { + this.presetCache[uri] = PluginPreset.deserialize_array(result); + resolve(result); + }) + .catch((error) => { + reject(error); + }) + } + }); + } + + loadPluginPreset(instanceId: number, presetName: string): void { + this.webSocket?.send("loadPluginPreset", { instanceId: instanceId, presetName: presetName }); + } + + shutdown(): Promise { + return this.webSocket!.request("shutdown"); + } + restart(): Promise { + return this.webSocket!.request("restart"); + + } + getJackServerSettings(): Promise { + return this.webSocket!.request("getJackServerSettings") + .then((data) => { + return new JackServerSettings().deserialize(data); + }); + } + setJackServerSettings(jackServerSettings: JackServerSettings): void { + this.webSocket?.request("setJackServerSettings", jackServerSettings) + .catch((error) => { + this.showAlert(error); + }); + } + setMidiBinding(instanceId: number, midiBinding: MidiBinding): void { + let pedalBoard = this.pedalBoard.get(); + if (!pedalBoard) { + throw new PiPedalStateError("Pedalboard not loaded."); + } + let newPedalBoard = pedalBoard.clone(); + if (newPedalBoard.setMidiBinding(instanceId, midiBinding)) { + this.pedalBoard.set(newPedalBoard); + // notify the server. + // TODO: a more efficient notification. + this.updateServerPedalBoard() + + } + } + midiListeners: MidiEventListener[] = []; + + nextListenHandle = 1; + listenForMidiEvent(listenForControlsOnly: boolean, onComplete: (isNote: boolean, noteOrControl: number) => void): ListenHandle { + let handle = this.nextListenHandle++; + + this.midiListeners.push(new MidiEventListener(handle, onComplete)); + + this.webSocket?.send("listenForMidiEvent", { listenForControlsOnly: listenForControlsOnly, handle: handle }); + return { + _handle: handle + }; + + } + + handleNotifyMidiListener(clientHandle: number, isNote: boolean, noteOrControl: number) { + for (let i = 0; i < this.midiListeners.length; ++i) { + let listener = this.midiListeners[i]; + if (listener.handle === clientHandle) { + listener.callback(isNote, noteOrControl); + + this.midiListeners.splice(i, 1); + } + } + } + cancelListenForMidiEvent(listenHandle: ListenHandle): void { + for (let i = 0; i < this.midiListeners.length; ++i) { + if (this.midiListeners[i].handle === listenHandle._handle) { + this.midiListeners.splice(i, 1); + } + } + this.webSocket?.send("cancelListenForMidiEvent", listenHandle._handle); + } + + download(targetType: string, instanceId: number): void { + if (instanceId === -1) return; + let url = this.varServerUrl + targetType + "?id=" + instanceId; + window.open(url, "_blank"); + } + + uploadPreset(file: File, uploadAfter: number): Promise { + let result = new Promise((resolve, reject) => { + try { + if (file.size > this.maxUploadSize) + { + reject("File is too large."); + } + let url = this.varServerUrl + "uploadPreset"; + if (uploadAfter && uploadAfter !== -1) { + url += "?uploadAfter=" + uploadAfter; + } + fetch( + url, + { + method: "POST", + body: file, + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then((response: Response) => { + if (!response.ok) { + reject("Upload failed. " + response.statusText); + return; + } else { + return response.json(); // read the empty body to keep the connection alive. + } + }) + .then((json) => { + resolve(json as number); + }) + .catch((error) => { + reject("Upload failed. " + error); + }) + ; + } catch (error) { + reject("Upload failed. " + error); + } + }); + return result; + } + +}; + +let instance: PiPedalModel | undefined = undefined; + + + +export class PiPedalModelFactory { + static getInstance(): PiPedalModel { + if (instance === undefined) { + let impl: PiPedalModelImpl = new PiPedalModelImpl(); + instance = impl; + + impl.initialize(); + } + return instance; + + } +}; + + + diff --git a/react/src/PiPedalSocket.tsx b/react/src/PiPedalSocket.tsx new file mode 100644 index 0000000..aacfa2c --- /dev/null +++ b/react/src/PiPedalSocket.tsx @@ -0,0 +1,269 @@ +import { PiPedalStateError } from './PiPedalError'; +import Utility from './Utility'; + +export type MessageHandler = (header: PiPedalMessageHeader, body: any | null) => void; +export type ErrorHandler = (message: string, exception?: Error) => void; +export type ReconnectHandler = () => void; +export type ReconnectingHandler = (retry: number, maxRetries: number) => void; + +const MAX_RETRIES = 6; +const MAX_RETRY_TIME = 90*1000; + +export type PiPedalMessageHeader = { + replyTo?: number; + reply?: number; + message: string; +} +type ReplyHandler = (header: PiPedalMessageHeader, body: any | null) => void; + + + + +class PiPedalSocket { + onMessageReceived: MessageHandler; + onError: ErrorHandler; + onReconnecting: ReconnectingHandler; + onReconnect: ReconnectHandler; + + socket?: WebSocket; + nextResponseCode: number = 0; + url: string; + retrying: boolean = false; + retryCount: number = 0; + retryDelay: number = 0; + totalRetryDelay: number = 0; + + constructor( + url: string, + onMessageReceived: MessageHandler, + onError: ErrorHandler, + onReconnecting: ReconnectingHandler, + onReconnect: ReconnectHandler) { + this.url = url; + this.onMessageReceived = onMessageReceived; + this.onError = onError; + this.onReconnecting = onReconnecting; + this.onReconnect = onReconnect; + } + + handleOpen(event: Event): any { + + } + + sendInternal_(json: string) { + if (!this.retrying) { + this.socket?.send(json); + } + } + send(message: string, jsonObject?: any) { + let msg: any; + if (jsonObject === undefined) { + msg = [{ message: message }]; + } else { + msg = [{ message: message }, jsonObject]; + } + let json = JSON.stringify(msg); + this.sendInternal_(json); + } + reply(replyTo: number, message: string, jsonObject?: any) { + if (replyTo !== -1) { + let msg: any; + if (jsonObject === undefined) { + msg = [{ reply: replyTo, message: message }]; + } else { + msg = [{ reply: replyTo, message: message }, jsonObject]; + } + let json = JSON.stringify(msg); + this.sendInternal_(json); + } + } + + _nextResponseCode(): number { + return ++this.nextResponseCode; + } + + _replyMap: Map = new Map(); + + _discardReplyReservations() + { + // it's ok. All pending reservations disappear into the GC. + this._replyMap = new Map(); + } + + + _addReservation(replyCode: number, handler: ReplyHandler): void { + this._replyMap.set(replyCode, handler); + } + + request(message_: string, requestArgs?: any): Promise { + let responseCode = this._nextResponseCode(); + + return new Promise((resolve, reject) => { + try { + this._addReservation(responseCode, (header: PiPedalMessageHeader, jsonObject?: any) => { + if (header.message === "error") { + reject(jsonObject + ""); + } else { + resolve(jsonObject as Type); + } + }); + let msg: any; + if (requestArgs !== undefined) { + msg = [{ message: message_, replyTo: responseCode }, requestArgs]; + } else { + msg = [{ message: message_, replyTo: responseCode }]; + } + let jsonMessage = JSON.stringify(msg); + this.sendInternal_(jsonMessage); + } catch (err) { + reject(err); + } + }); + } + handleMessage(event: MessageEvent): any { + try { + let message: any = JSON.parse(event.data); + if (!Array.isArray(message)) { + throw new PiPedalStateError("Invalid message received from server."); + } + let header = message[0] as PiPedalMessageHeader; + let body = undefined; + if (message.length === 2) { + body = message[1]; + } + if (header.reply !== undefined) { + let handler = this._replyMap.get(header.reply); + if (handler) { + handler(header, body); + } + return; + } else { + if (header.message === "error") { + throw new PiPedalStateError("Server error: " + body); + } + this.onMessageReceived(header, body); + } + } catch (error) { + if (this.onError) { + this.onError("Invalid server response. " + error, error); + } else { + throw new PiPedalStateError("Invalid server response."); + } + } + } + + handleError(_event: Event): any { + if (this.onError) { + this.onError("Server connection lost."); + } else { + throw new PiPedalStateError("Server connection lost."); + } + } + handleClose(_event: any): any { + if (this.retrying) { + // treat this as a fatal error. + if (this.onError) { + this.onError("Server connection lost."); + } else { + throw new PiPedalStateError("Server connection closed."); + } + return; + + } + this._discardReplyReservations(); + this.retrying = true; + this.retryCount = 0; + this.socket = undefined; + this.retryDelay = 10000; + this.totalRetryDelay = 0; + + this.reconnect(); + } + + reconnect() { + + if (this.socket) + { + this.close(); + } + + this.onReconnecting(this.retryCount,MAX_RETRIES); + ++this.retryCount; + + this.connectInternal_() + .then((socket) => { + this.socket = socket; + this.retrying = false; + this.onReconnect(); + }) + .catch(error => { + if (this.totalRetryDelay === MAX_RETRY_TIME) + { + this.onError("Server connection lost."); + return; + } else { + this.totalRetryDelay += this.retryDelay; + Utility.delay(this.retryDelay).then(() => this.reconnect()); + this.retryDelay *= 2; + if (this.retryDelay > 5000) this.retryDelay = 5000; + } + }); + } + + close(): void { + try { + if (this.socket) + { + this.socket.onclose = null; + this.socket.onerror = null; + this.socket.onmessage = null; + this.socket.onopen = null; + this.socket?.close(); + } + } catch (ignored) + { + + } + this.socket = undefined; + } + connectInternal_(): Promise { + return new Promise((resolve, reject) => { + let ws = new WebSocket(this.url); + let self = this; + + ws.onmessage = this.handleMessage.bind(this); + ws.onclose = (event: Event) => { + ws.onclose = null; + ws.onerror = null; + reject("Can't connect to server."); + }; + ws.onerror = (event: Event) => { + ws.onclose = null; + ws.onerror = null; + reject("Can't connect to server."); + }; + ws.onopen = (event: Event) => { + ws.onerror = self.handleError.bind(self); + ws.onclose = self.handleClose.bind(self); + ws.onopen = null; + resolve(ws); + }; + }); + } + connect(): Promise { + return new Promise((resolve, reject) => { + + this.connectInternal_() + .then((socket) => { + this.socket = socket; + resolve(); + }) + .catch((reason) => { + reject(reason); + }); + }); + } + +} + +export default PiPedalSocket; diff --git a/react/src/PluginClass.tsx b/react/src/PluginClass.tsx new file mode 100644 index 0000000..a5bc3c3 --- /dev/null +++ b/react/src/PluginClass.tsx @@ -0,0 +1,63 @@ +import {PluginType} from './Lv2Plugin'; + +class PluginClass { + deserialize(input: any) : PluginClass { + this.uri = input.uri; + this.display_name = input.display_name; + this.parent_uri = input.parent_uri; + this.plugin_type = input.plugin_type as PluginType; + this.children = PluginClass.deserialize_array(input.children); + return this; + } + static deserialize_array(input: any): PluginClass[] { + let result: PluginClass[] = []; + for (let i = 0; i < input.length; ++i) + { + result[i] = new PluginClass().deserialize(input[i]); + } + + return result; + + } + findChild(classUri: string): PluginClass | null { + if (this.uri === classUri) return this; + for (let i = 0; i < this.children.length; ++i) + { + let t = this.children[i].findChild(classUri); + if (t != null) return t; + } + return null; + } + findChildType(pluginType: PluginType): PluginClass | null { + if (this.plugin_type === pluginType) return this; + for (let i = 0; i < this.children.length; ++i) + { + let t = this.children[i].findChildType(pluginType); + if (t != null) return t; + } + return null; + } + + + + is_a(parentClassUri: string,childClassUri: string): boolean { + let parent = this.findChild(parentClassUri); + if (parent === null) return false; + let child = parent.findChild(childClassUri); + return child != null; + } + is_type_of(parentType: PluginType,childType: PluginType): boolean { + let parent = this.findChildType(parentType); + if (parent === null) return false; + let child = parent.findChildType(childType); + return child != null; + } + + uri: string = ""; + display_name: string = ""; + parent_uri: string = ""; + plugin_type: PluginType = PluginType.Plugin; + children: PluginClass[] = []; +} + +export default PluginClass; \ No newline at end of file diff --git a/react/src/PluginControl.tsx b/react/src/PluginControl.tsx new file mode 100644 index 0000000..d7a2c23 --- /dev/null +++ b/react/src/PluginControl.tsx @@ -0,0 +1,743 @@ +import React, { TouchEvent, PointerEvent, ReactNode, Component, SyntheticEvent } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { UiControl, ScalePoint } from './Lv2Plugin'; +import Typography from '@material-ui/core/Typography'; +import Input from '@material-ui/core/Input'; +import Select from '@material-ui/core/Select'; +import Switch from '@material-ui/core/Switch'; +import Units from './Units'; +import Utility, {nullCast} from './Utility'; +import MenuItem from '@material-ui/core/MenuItem'; + + +const MIN_ANGLE = -135; +const MAX_ANGLE = 135; +const FONT_SIZE = "0.8em"; + + + +const SELECTED_OPACITY = 0.8; +const DEFAULT_OPACITY = 0.6; +const RANGE_SCALE = 120; // 120 pixels to move from 0 to 1. +const FINE_RANGE_SCALE = RANGE_SCALE * 10; // 1200 pixels to move from 0 to 1. +const ULTRA_FINE_RANGE_SCALE = RANGE_SCALE * 50; // 12000 pixels to move from 0 to 1. + + +export const StandardItemSize = { width: 80, height: 140 } + + + +const styles = (theme: Theme) => createStyles({ + frame: { + position: "relative", + margin: "12px" + }, + switchTrack: { + height: '100%', + width: '100%', + borderRadius: 14 / 2, + zIndex: -1, + transition: theme.transitions.create(['opacity', 'background-color'], { + duration: theme.transitions.duration.shortest + }), + backgroundColor: theme.palette.secondary.main, + opacity: theme.palette.type === 'light' ? 0.38 : 0.3 + }, + displayValue: { + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 4, + textAlign: "center", + background: "white", + color: "#666", + // zIndex: -1, + } +}); + + +export interface PluginControlProps extends WithStyles { + uiControl?: UiControl; + value: number; + onPreviewChange?: (value: number) => void; + onChange: (value: number) => void; + theme: Theme; + requestIMEEdit: (uiControl: UiControl, value: number) => void; +}; +type PluginControlState = { + error: boolean; +}; + +const PluginControl = + withStyles(styles, { withTheme: true })( + class extends Component + { + imgRef: React.RefObject; + inputRef: React.RefObject; + selectRef: React.RefObject; + + displayValueRef: React.RefObject; + + constructor(props: PluginControlProps) { + super(props); + + this.state = { + error: false + }; + + this.imgRef = React.createRef(); + this.inputRef = React.createRef(); + this.selectRef = React.createRef(); + this.displayValueRef = React.createRef(); + + + this.onPointerDown = this.onPointerDown.bind(this); + this.onPointerUp = this.onPointerUp.bind(this); + this.onPointerMove = this.onPointerMove.bind(this); + this.onPointerLostCapture = this.onPointerLostCapture.bind(this); + this.onBodyPointerDownCapture = this.onBodyPointerDownCapture.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + //this.onTouchCancel = this.onTouchCancel.bind(this); + + this.onSelectChanged = this.onSelectChanged.bind(this); + this.onInputChange = this.onInputChange.bind(this); + this.onInputLostFocus = this.onInputLostFocus.bind(this); + this.onInputFocus = this.onInputFocus.bind(this); + this.onInputKeyPress = this.onInputKeyPress.bind(this); + } + + inputChanged: boolean = false; + + onInputLostFocus(event: any): void { + if (this.inputChanged) // validation requried? + { + this.inputChanged = false; + this.validateInput(event, true); + + } + this.displayValueRef.current!.style.display = "block"; + } + onInputFocus(event: SyntheticEvent): void { + this.displayValueRef.current!.style.display = "none"; + if (Utility.hasIMEKeyboard()) + { + event.preventDefault(); + event.stopPropagation(); + this.inputRef.current?.blur(); + this.props.requestIMEEdit(nullCast(this.props.uiControl),this.props.value) + } + } + onInputKeyPress(e: any): void { + if (e.charCode === 13 && this.inputChanged) { + this.inputChanged = false; + this.validateInput(e, true); + } + } + + onInputChange(event: any): void { + this.inputChanged = true; + this.validateInput(event, false); + } + validateInput(event: any, commitValue: boolean) { + if (!this.inputRef.current) return; + + let text = this.inputRef.current.value; + let valid = false; + let result: number = this.currentValue; + try { + if (text.length === 0) { + valid = false; + } else { + let v = Number(text); + if (isNaN(v)) { + valid = false; + } else { + valid = true; + result = v; + } + } + } catch (error) { + valid = false; + } + + if (commitValue) { + this.setState({ error: false }); + if (!valid) { + result = this.currentValue; // reset the value! + } + // clamp and quantize. + let range = this.valueToRange(result); + result = this.rangeToValue(range); + if (event.currentTarget) { + event.currentTarget.value = this.formatValue(this.props.uiControl, result); + } + this.previewInputValue(result, true); + this.inputRef.current.value = this.formatValue(this.props.uiControl, result); // no rerender because the value won't change. + } else { + this.setState({ error: !valid }); + if (valid) { + this.previewInputValue(result, false); + } + } + } + + startX: number = 0; + startY: number = 0; + mouseDown: boolean = false; + + onDrag(e: SyntheticEvent) { + e.preventDefault(); + } + + isValidPointer(e: PointerEvent): boolean { + if (e.pointerType === "mouse") { + return e.button === 0; + } else if (e.pointerType === "pen") { + return true; + } else if (e.pointerType === "touch") { + return true; + } + return false; + } + + touchDown: boolean = false; + touchIdentifier: number = -1; + + onTouchStart(e: TouchEvent) { + } + onTouchMove(e: TouchEvent) { + // e.preventDefault(); + e.stopPropagation(); // cancels scroll!!! + + } + + capturedPointers: number[] = []; + + onBodyPointerDownCapture(e_: any): any + { + let e = e_ as PointerEvent; + if (this.isExtraTouch(e)) + { + this.captureElement!.setPointerCapture(e.pointerId); + this.capturedPointers.push(e.pointerId); + ++this.pointersDown; + } + + } + + pointerId: number = 0; + pointerType: string = ""; + + isCapturedPointer(e: PointerEvent): boolean { + return this.mouseDown + && e.pointerId === this.pointerId + && e.pointerType === this.pointerType; + + } + + lastX: number = 0; + lastY: number = 0; + dRange: number = 0; + + pointersDown: number = 0; + captureElement?: HTMLElement = undefined; + + onPointerDown(e: PointerEvent): void { + if (!this.mouseDown && this.isValidPointer(e)) { + ++this.pointersDown; + + + e.preventDefault(); + e.stopPropagation(); + + this.mouseDown = true; + + this.pointerId = e.pointerId; + this.pointerType = e.pointerType; + this.startX = e.clientX; + this.startY = e.clientY; + this.lastX = e.clientX; + this.lastY = e.clientY; + this.dRange = 0; + + let img = this.imgRef.current; + + if (img) { + this.captureElement = img; + document.body.addEventListener( + "pointerdown", + this.onBodyPointerDownCapture,true + ); + + img.setPointerCapture(e.pointerId); + if (img.style) { + img.style.opacity = "" + SELECTED_OPACITY; + } + } + + } else { + if (this.isExtraTouch(e)) + { + ++this.pointersDown; + + } + } + } + isExtraTouch(e: PointerEvent): boolean { + return (this.mouseDown && this.pointerType === "touch" && e.pointerType === "touch" && e.pointerId !== this.pointerId); + + } + + onPointerLostCapture(e: PointerEvent) { + if (this.isCapturedPointer(e)) { + --this.pointersDown; + + + this.releaseCapture(e); + } + + } + + updateRange(e: PointerEvent): number { + + let ultraHigh = false; + let high = false; + if (e.ctrlKey) + { + ultraHigh = true; + } + if (e.shiftKey) + { + high = true; + } + if (e.pointerType === "touch") + { + if (this.pointersDown >= 3) + { + ultraHigh = true; + } else if (this.pointersDown === 2) + { + high = true; + } + } + if (ultraHigh) { + this.dRange += (this.lastY - e.clientY) / ULTRA_FINE_RANGE_SCALE; + + } else if (high) { + this.dRange += (this.lastY - e.clientY) / FINE_RANGE_SCALE; + + } else { + this.dRange += (this.lastY - e.clientY) / RANGE_SCALE; + } + this.lastY = e.clientY; + this.lastX = e.clientX; + return this.dRange; + } + onPointerUp(e: PointerEvent) { + + if (this.isCapturedPointer(e)) { + --this.pointersDown; + + + e.preventDefault(); + let dRange = this.updateRange(e) + this.previewRange(dRange, true); + + this.releaseCapture(e); + + } else { + --this.pointersDown; + + } + } + + releaseCapture(e: PointerEvent) + { + let img = this.imgRef.current; + + if (img && img.style) { + img.releasePointerCapture(e.pointerId); + img.style.opacity = "" + DEFAULT_OPACITY; + // they get automaticlly released. + // for (let i = 0; i < this.capturedPointers.length; ++i) + // { + // img.releasePointerCapture (this.capturedPointers[i]); + // } + this.capturedPointers = []; + } + document.body.removeEventListener( + "pointerdown", + this.onBodyPointerDownCapture,true + ); + + this.mouseDown = false; + + } + + onPointerMove(e: PointerEvent): void { + if (this.isCapturedPointer(e)) { + e.preventDefault(); + let dRange = this.updateRange(e) + this.previewRange(dRange, false); + } + } + + previewInputValue(value: number, commitValue: boolean) { + let range = this.valueToRange(value); + value = this.rangeToValue(range); + + let transform = this.rangeToRotationTransform(range); + if (this.mouseDown && !commitValue) { + transform += " scale(1.5, 1.5)"; + } + let imgElement = this.imgRef.current + if (imgElement) { + if (imgElement.style) { + imgElement.style.transform = transform; + } + } + if (commitValue) { + this.props.onChange(value); + } + if (this.props.onPreviewChange) { + this.props.onPreviewChange(value); + } + + } + previewRange(dRange: number, commitValue: boolean): void { + let range = this.valueToRange(this.currentValue) + dRange; + if (range > 1) range = 1; + if (range < 0) range = 0; + let value = this.rangeToValue(range); + + // apply value quantization and clipping. + range = this.valueToRange(value); + + let imgElement = this.imgRef.current + if (imgElement) { + if (imgElement.style) { + imgElement.style.transform = this.rangeToRotationTransform(range); + } + } + let inputElement = this.inputRef.current; + if (inputElement) { + let v = this.formatValue(this.props.uiControl, value); + inputElement.value = v; + } + let displayValue = this.displayValueRef.current; + if (displayValue) + { + let v = this.formatDisplayValue(this.props.uiControl,value); + displayValue.childNodes[0].textContent = v; + } + let selectElement = this.selectRef.current; + if (selectElement) { + //let v = this.formatValue(this.props.uiControl,value); + selectElement.selectedIndex = value; + + } + if (commitValue) { + this.currentValue = value; + this.props.onChange(value); + } else { + if (this.props.onPreviewChange) { + this.props.onPreviewChange(value); + } + } + } + + onCheckChanged(checked: boolean): void { + this.props.onChange(checked ? 1 : 0); + } + onSelectChanged(e: any, value: any) { + let target = e.target; + setTimeout(()=> { + this.props.onChange(target.value); + },0); + + + } + + makeSelect(control: UiControl, value: number): ReactNode { + if (control.isOnOffSwitch()) { + // normal gray unchecked state. + return ( + { + this.onCheckChanged(event.target.checked); + }} + /> + ); + } + if (control.isAbToggle()) { + // unchecked color is not gray. + return ( + { + this.onCheckChanged(event.target.checked); + }} + classes={{ + track: this.props.classes.switchTrack + }} + style={{ color: this.props.theme.palette.secondary.main }} + /> + ); + } else { + return ( + + ); + } + } + + formatDisplayValue(uiControl: UiControl | undefined, value: number): string { + if (!uiControl) return ""; + for (let i = 0; i < uiControl.scale_points.length; ++i) + { + let scalePoint = uiControl.scale_points[i]; + if (scalePoint.value === value) + { + return scalePoint.label; + } + } + let text = this.formatValue(uiControl, value); + + switch (uiControl.units) { + case Units.bpm: + text += "bpm"; + break; + case Units.cent: + text += "cents"; + break; + case Units.cm: + text += "cm"; + break; + case Units.db: + text += "dB"; + break; + case Units.hz: + text += "Hz"; + break; + case Units.khz: + text += "kHz"; + break; + case Units.km: + text += "km"; + break; + case Units.m: + text += "m"; + break; + case Units.mhz: + text += "MHz"; + break; + case Units.min: + text += "min"; + break; + case Units.ms: + text += "ms"; + break; + case Units.pc: + text += "%"; + break; + case Units.s: + text += "s"; + break; + // Midinote: not handled. + // semitone12TET not handled. + + + + } + return text; + + + } + formatValue(uiControl: UiControl | undefined, value: number): string { + if (!uiControl) return ""; + return uiControl.formatValue(value); + } + + valueToRange(value: number): number { + let uiControl = this.props.uiControl; + if (uiControl) { + if (uiControl.integer_property) { + value = Math.round(value); + } + let range: number; + if (uiControl.is_logarithmic) + { + range = Math.log(value/uiControl.min_value)/Math.log(uiControl.max_value/uiControl.min_value); + if (uiControl.range_steps > 1) { + range = Math.round(range*(uiControl.range_steps-1))/(uiControl.range_steps-1); + } + } else { + range = (value - uiControl.min_value) / (uiControl.max_value - uiControl.min_value); + } + if (range > 1) range = 1; + if (range < 0) range = 0; + return range; + } + return 0; + } + rangeToValue(range: number): number { + if (range < 0) range = 0; + if (range > 1) range = 1; + let uiControl = this.props.uiControl; + if (uiControl) { + if (uiControl.range_steps > 1) { + range = Math.round(range * uiControl.range_steps-1) / (uiControl.range_steps-1); + } + let value: number; + if (uiControl.is_logarithmic) + { + value = uiControl.min_value*Math.pow(uiControl.max_value/uiControl.min_value,range); + } else { + value = range * (uiControl.max_value - uiControl.min_value) + uiControl.min_value; + } + if (uiControl.integer_property) { + value = Math.round(value); + } + return value; + } + return 0; + } + + rangeToRotationTransform(range: number): string { + let angle = range * (MAX_ANGLE - MIN_ANGLE) + MIN_ANGLE; + return "rotate(" + angle + "deg)"; + } + + getRotationTransform(): string { + let range = 0; + let uiControl = this.props.uiControl; + if (uiControl) { + let value = this.props.value; + range = this.valueToRange(value); + } + return this.rangeToRotationTransform(range); + } + + currentValue: number = 0; + uiControl?: UiControl = undefined; + + render() { + let classes = this.props.classes; + let t = this.props.uiControl; + if (!t) { + return (
#Error
); + + } + let control: UiControl = t; + this.uiControl = control; + let value = this.props.value; + this.currentValue = value; + let switchText = ""; + + let isSelect = control.isSelect(); + let isAbSwitch = control.isAbToggle(); + let isOnOffSwitch = control.isOnOffSwitch(); + + if (isAbSwitch) { + switchText = control.scale_points[0].value === value ? control.scale_points[0].label : control.scale_points[1].label; + } + + let item_width = isSelect ? 160 : 80; + + + return ( +
+ {/* TITLE SECTION */} +
+ {control.name} +
+ {/* CONTROL SECTION */} + +
+ {(isSelect || isAbSwitch || isOnOffSwitch) ? ( + this.makeSelect(control, value) + ) : ( +
+ {control.name} +
+ ) + } +
+ + {/* LABEL/EDIT SECTION*/} +
+ {(!(isSelect || isOnOffSwitch)) && + ( + (isAbSwitch) ? ( + {switchText} + ) : ( +
+ +
{ this.inputRef.current!.focus(); }} > + + {this.formatDisplayValue(control, value)} +
+
+ ) + ) + } +
+
+ ); + } + /* + isSamePointer(PointerEvent e): boolean + { + return e.pointerId === this.pointerId + && e.pointerType === this.pointerType; + } + */ + touchPointerId: number = 0; + + + } + ); + +export default PluginControl; \ No newline at end of file diff --git a/react/src/PluginControlView.tsx b/react/src/PluginControlView.tsx new file mode 100644 index 0000000..4da3a83 --- /dev/null +++ b/react/src/PluginControlView.tsx @@ -0,0 +1,488 @@ +import { ReactNode } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { UiPlugin, UiControl } from './Lv2Plugin'; +import { + PedalBoard, PedalBoardItem, ControlValue, +} from './PedalBoard'; +import PluginControl from './PluginControl'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import VuMeter from './VuMeter'; +import { nullCast } from './Utility' +import GxTunerControl from './GxTunerControl'; +import { PiPedalStateError } from './PiPedalError'; +import Typography from '@material-ui/core/Typography'; +import FullScreenIME from './FullScreenIME'; + + +export const StandardItemSize = { width: 80, height: 110 }; + + +const GXTUNER_URI = "http://guitarix.sourceforge.net/plugins/gxtuner#tuner"; + +const LANDSCAPE_HEIGHT_BREAK = 500; + +const styles = (theme: Theme) => createStyles({ + frame: { + display: "block", + position: "relative", + flexDirection: "row", + flexWrap: "nowrap", + paddingTop: "8px", + paddingBottom: "0px", + height: "100%", + overflowX: "auto", + overflowY: "auto" + }, + vuMeterL: { + position: "fixed", + paddingLeft: 12, + paddingRight: 4, + paddingBottom: 24, + left: 0, + background: "white", + zIndex: 3 + + }, + vuMeterR: { + position: "fixed", + right: 0, + marginRight: 22, + paddingLeft: 4, + paddingBottom: 24, + background: "white", + zIndex: 3 + + }, + vuMeterRLandscape: { + position: "fixed", + right: 0, + paddingRight: 22, + paddingLeft: 12, + paddingBottom: 24, + background: "white", + zIndex: 3 + + }, + + normalGrid: { + position: "relative", + paddingLeft: 22, + paddingRight: 34, + flex: "1 1 auto", + display: "flex", flexDirection: "row", flexWrap: "wrap", + justifyContent: "flex-start", alignItems: "flex_start", + + + }, + landscapeGrid: { + paddingLeft: 40, + // marginRight: 40, : bug in chrome layout engine wrt/ right margin/padding. See the spacer div added after all controls in render() with provides the same effect. + display: "flex", flexDirection: "row", flexWrap: "nowrap", + justifyContent: "flex-start", alignItems: "flex_start", + flex: "0 0 auto" + }, + portgroupControlPadding: { + flex: "0 0 auto", + marginTop: 12, + marginBottom: 8 + + }, + controlPadding: { + flex: "0 0 auto", + marginTop: 0, + marginBottom: 0 + + }, + portGroup: { + marginLeft: 8, + marginTop: 0, + marginRight: 8, + marginBottom: 12, + position: "relative", + paddingLeft: 0, + paddingRight: 0, + paddingTop: 0, + paddingBottom: 0, + border: "2pt #AAA solid", + borderRadius: 10, + elevation: 12, + display: "flex", + flexDirection: "row", flexWrap: "wrap", + flex: "0 1 auto", + }, + portGroupLandscape: { + marginLeft: 8, + marginTop: 0, + marginRight: 8, + marginBottom: 12, + position: "relative", + paddingLeft: 0, + paddingRight: 0, + paddingTop: 0, + paddingBottom: 0, + border: "2pt #AAA solid", + borderRadius: 10, + elevation: 12, + display: "flex", + flexDirection: "row", flexWrap: "nowrap", + flex: "0 0 auto" + }, + portGroupTitle: { + position: "absolute", + top: -10, + background: "white", + marginLeft: 20, + paddingLeft: 8, + paddingRight: 8 + }, + portGroupControls: { + display: "flex", + flexDirection: "row", flexWrap: "wrap", + paddingTop: 6, + paddingBottom: 8 + } + + +}); + +export class ControlGroup { + constructor(name: string, controls: ReactNode[]) + { + this.name = name; + this.controls = controls; + } + name: string; + controls: React.ReactNode[]; +} + +export type ControlNodes = (ReactNode | ControlGroup)[]; + + +export interface ControlViewCustomization { + ModifyControls(controls: (React.ReactNode | ControlGroup)[]): (React.ReactNode | ControlGroup)[]; + +}; + +export interface PluginControlViewProps extends WithStyles { + theme: Theme; + instanceId: number; + item: PedalBoardItem; + customization?: ControlViewCustomization; + customizationId?: number; +}; +type PluginControlViewState = { + landscapeGrid: boolean; + imeUiControl?: UiControl; + imeValue: number; + imeCaption: string; + imeInitialHeight: number; +}; + +const PluginControlView = + withStyles(styles, { withTheme: true })( + class extends ResizeResponsiveComponent + { + model: PiPedalModel; + + constructor(props: PluginControlViewProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.state = { + landscapeGrid: false, + imeUiControl: undefined, + imeValue: 0, + imeCaption: "", + imeInitialHeight: 0 + + } + this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this); + this.onValueChanged = this.onValueChanged.bind(this); + this.onPreviewChange = this.onPreviewChange.bind(this); + } + + + onPreviewChange(key: string, value: number): void { + this.model.previewPedalBoardValue(this.props.instanceId, key, value); + } + + onValueChanged(key: string, value: number): void { + this.model.setPedalBoardControlValue(this.props.instanceId, key, value); + } + + onPedalBoardChanged(value?: PedalBoard) { + //let item = this.model.pedalBoard.get().maybeGetItem(this.props.instanceId); + //this.setState({ pedalBoardItem: item }); + } + + + componentDidMount() { + super.componentDidMount(); + this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged); + } + componentWillUnmount() { + this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged); + super.componentWillUnmount(); + } + + + onWindowSizeChanged(width: number, height: number): void { + this.setState({ landscapeGrid: height < LANDSCAPE_HEIGHT_BREAK }); + } + filterNotOnGui(controlValues: ControlValue[], uiPlugin: UiPlugin): ControlValue[] { + let result: ControlValue[] = []; + + for (let i = 0; i < controlValues.length; ++i) { + let controlValue = controlValues[i]; + let control = uiPlugin.getControl(controlValue.key); + if (control && !control.not_on_gui) { + result.push(controlValue); + } + } + return result; + } + + requestImeEdit(uiControl: UiControl, value: number) { + // eslint-disable-next-line no-restricted-globals + + this.setState({ + imeUiControl: uiControl, + imeValue: value, + imeCaption: uiControl.name, + imeInitialHeight: window.innerHeight + + }); + } + makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode { + let symbol = uiControl.symbol; + + let controlValue: ControlValue | undefined = undefined; + for (let i = 0; i < controlValues.length; ++i) { + if (controlValues[i].key === symbol) { + controlValue = controlValues[i]; + break; + } + } + if (!controlValue) { + throw new PiPedalStateError("Missing control value."); + } + return (( + + { this.onValueChanged(controlValue!.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(controlValue!.key, value) }} + requestIMEEdit={(uiControl, value) => this.requestImeEdit(uiControl, value)} + + /> + )); + + } + + getStandardControlNodes(plugin: UiPlugin, controlValues: ControlValue[]): ControlNodes { + let result: ControlNodes = []; + + for (let i = 0; i < plugin.controls.length; ++i) { + let pluginControl = plugin.controls[i]; + if (!pluginControl.not_on_gui) { + if (pluginControl.port_group !== "") { + let portGroup = pluginControl.port_group; + let groupControls: ReactNode[] = []; + groupControls.push( + this.makeStandardControl(pluginControl, controlValues) + ); + while (i + 1 < plugin.controls.length && plugin.controls[i + 1].port_group === portGroup) { + ++i; + pluginControl = plugin.controls[i]; + if (!pluginControl.not_on_gui) { + groupControls.push( + this.makeStandardControl(pluginControl, controlValues) + ) + } + } + result.push( + new ControlGroup(plugin.getPortGroup(portGroup).name, groupControls) + ) + } else { + result.push( + this.makeStandardControl(pluginControl, controlValues) + ); + } + } + } + return result; + } + + getControl(controlValues: ControlValue[], key: string) { + for (let i = 0; i < controlValues.length; ++i) { + if (controlValues[i].key === key) { + return controlValues[i]; + } + } + throw new Error("Not found."); + } + + getTunerControls(plugin: UiPlugin, controlValues: ControlValue[]): ControlNodes { + // display standard version of just a few controls. + let shortList: ControlValue[] = []; + // for (let i = 0; i < controlValues.length; ++i) + // { + // shortList.push(controlValues[i]); + // } + shortList.push(this.getControl(controlValues, "REFFREQ")); + shortList.push(this.getControl(controlValues, "THRESHOLD")); + + + let controls = shortList.map((controlValue) => ( + { this.onValueChanged(controlValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(controlValue.key, value) }} + requestIMEEdit={(uiControl, value) => this.requestImeEdit(uiControl, value)} + /> + )); + let tunerControl = (); + let result: ControlNodes = []; + result.push(tunerControl); + + for (let i = 0; i < controls.length; ++i) + { + result.push(controls[i]); + } + + return result; + } + onImeValueChange(key: string, value: number) { + this.model.setPedalBoardControlValue(this.props.instanceId, key, value); + this.onImeClose(); + } + onImeClose() { + this.setState({ + imeUiControl: undefined + }); + } + + hasGroups(nodes: (ReactNode | ControlGroup)[]): boolean + { + for (let i = 0; i < nodes.length; ++i) + { + let node = nodes[i]; + if (node instanceof ControlGroup) return true; + } + return false; + } + + controlNodesToNodes(nodes: (ReactNode | ControlGroup)[]): ReactNode[] { + let classes = this.props.classes; + let isLandscapeGrid = this.state.landscapeGrid; + let hasGroups = this.hasGroups(nodes); + + let result: ReactNode[] = []; + + for (let i = 0; i < nodes.length; ++i) { + let node = nodes[i]; + if (node instanceof ControlGroup) { + let controlGroup = node as ControlGroup; + let controls: ReactNode[] = []; + for (let j = 0; j < controlGroup.controls.length; ++j) + { + let item = controlGroup.controls[j]; + controls.push( + ( +
+ { item } +
+ + ) + ); + } + + result.push(( +
+
+ {controlGroup.name} +
+
+ { + controls + } +
+
+ )); + + } else { + result.push(( +
+ {node as ReactNode} +
+ )); + } + + } + return result; + } + + + render(): ReactNode { + let classes = this.props.classes; + let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId); + + if (!pedalBoardItem) + return (
); + + let controlValues = pedalBoardItem.controlValues; + + + let plugin: UiPlugin = nullCast(this.model.getUiPlugin(pedalBoardItem.uri)); + + + controlValues = this.filterNotOnGui(controlValues, plugin); + + + let gridClass = this.state.landscapeGrid ? classes.landscapeGrid : classes.normalGrid; + let vuMeterRClass = this.state.landscapeGrid ? classes.vuMeterRLandscape : classes.vuMeterR; + let controlNodes: ControlNodes; + + if (plugin.uri === GXTUNER_URI) { + controlNodes = this.getTunerControls(plugin, controlValues); + } else { + controlNodes = this.getStandardControlNodes(plugin, controlValues); + } + if (this.props.customization) + { + // allow wrapper class to insert/remove/rebuild controls. + controlNodes = this.props.customization.ModifyControls(controlNodes); + } + + let nodes = this.controlNodesToNodes(controlNodes); + + return ( +
+
+ +
+
+ +
+
+ { + nodes + } +
+
+ this.onImeValueChange(key, value)} + initialHeight={ + this.state.imeInitialHeight} + caption={this.state.imeCaption} + onClose={() => this.onImeClose()} /> +
+ ); + + } + + } + ); + +export default PluginControlView; + diff --git a/react/src/PluginIcon.tsx b/react/src/PluginIcon.tsx new file mode 100644 index 0000000..f7a43bb --- /dev/null +++ b/react/src/PluginIcon.tsx @@ -0,0 +1,145 @@ +import { createStyles, Theme, withStyles, WithStyles } from '@material-ui/core/styles'; +import { PiPedalModelFactory } from "./PiPedalModel"; +import { PluginType } from './Lv2Plugin'; + + +const styles = (theme: Theme) => + createStyles({ + icon: { + width: "24px", + height: "24px", + margin: "0px", + opacity: "0.6" + }, + }); + +export interface PluginIconProps extends WithStyles { + size?: number; + offsetY?: number; + pluginType: PluginType; + pluginUri: string; +} +export function SelectBaseIcon(plugin_type: PluginType): string { + switch (plugin_type) { + case PluginType.PhaserPlugin: + return "fx_phaser.svg"; + case PluginType.FilterPlugin: + return "fx_filter.svg"; + case PluginType.DelayPlugin: + return "fx_delay.svg"; + case PluginType.SimulatorPlugin: + return "fx_simulator.svg"; + case PluginType.AmplifierPlugin: + return "fx_amplifier.svg"; + case PluginType.ChorusPlugin: + return "fx_chorus.svg"; + case PluginType.ModulatorPlugin: + case PluginType.CombPlugin: + return "fx_modulator.svg"; + case PluginType.ReverbPlugin: + return "fx_reverb.svg"; + case PluginType.DistortionPlugin: + return "fx_distortion.svg"; + case PluginType.FlangerPlugin: + return "fx_flanger.svg"; + case PluginType.HighpassPlugin: + return "fx_highpass.svg"; + case PluginType.ParaEQPlugin: + case PluginType.LowpassPlugin: + case PluginType.MultiEQPlugin: + case PluginType.EQPlugin: + return "fx_eq.svg"; + case PluginType.UtilityPlugin: + return "fx_utility.svg"; + case PluginType.CompressorPlugin: + case PluginType.DynamicsPlugin: + case PluginType.ExpanderPlugin: + return "fx_compressor.svg"; + case PluginType.LimiterPlugin: + return "fx_limiter.svg"; + case PluginType.ConstantPlugin: + return "fx_constant.svg"; + case PluginType.FunctionPlugin: + case PluginType.WaveshaperPlugin: + return "fx_function.svg"; + case PluginType.GatePlugin: + return "fx_gate.svg"; + case PluginType.ConverterPlugin: + return "fx_converter.svg" + case PluginType.GeneratorPlugin: + return "fx_generator.svg"; + case PluginType.OscillatorPlugin: + return "fx_oscillator.svg"; + case PluginType.InstrumentPlugin: + return "fx_instrument.svg"; + case PluginType.MixerPlugin: + return "fx_mixer.svg"; + case PluginType.PitchPlugin: + return "fx_pitch.svg"; + case PluginType.SpatialPlugin: + return "fx_spatial.svg"; + case PluginType.SpectralPlugin: + return "fx_spectral.svg"; + case PluginType.AnalyserPlugin: + return "fx_analyzer.svg"; + case PluginType.Plugin: + default: + return "fx_plugin.svg"; + } +} + +var colors: string[] = [ + "#14003d", + "#630651", + "#005010", + "#281431", + "#5E0012", + "#401222", + "#3B1502" +]; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function colorFromHash(uri: string) { + let hash = hashString(uri); + + return colors[hash % colors.length]; + +} + +function hashString(str: string): number { + var hash = 0, i, chr; + for (i = 0; i < str.length; i++) { + chr = str.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; // Convert to 32bit integer + } + if (hash < 0) return -hash; + return hash; +} + +export function SelectIcon(plugin_type: PluginType, itemUri: string) { + let icon = SelectBaseIcon(plugin_type); + return PiPedalModelFactory.getInstance().svgImgUrl(icon); +} + +const PluginIcon = withStyles(styles)((props: PluginIconProps) => { + const { classes, pluginUri, pluginType } = props; + + let size: number = 24; + if (props.size) size = props.size; + let topVal: number = (props.offsetY ?? 0); + + return ( + {pluginType); + + // let maskText = "url(" + SelectIcon(pluginType, pluginUri) + ") no-repeat center"; + // let color=colorFromHash(pluginUri); + // return ( + //
 
+ // ); +}); + +export default PluginIcon; \ No newline at end of file diff --git a/react/src/PluginInfoDialog.tsx b/react/src/PluginInfoDialog.tsx new file mode 100644 index 0000000..70cfffb --- /dev/null +++ b/react/src/PluginInfoDialog.tsx @@ -0,0 +1,218 @@ +import React from 'react'; +import { createStyles, Theme, withStyles, WithStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import MuiDialogTitle from '@material-ui/core/DialogTitle'; +import MuiDialogContent from '@material-ui/core/DialogContent'; +import MuiDialogActions from '@material-ui/core/DialogActions'; +import IconButton from '@material-ui/core/IconButton'; +import CloseIcon from '@material-ui/icons/Close'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import { PiPedalModelFactory } from "./PiPedalModel"; +import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined'; +import { UiPlugin, UiControl } from './Lv2Plugin'; +import PluginIcon from './PluginIcon'; + + +const styles = (theme: Theme) => + createStyles({ + root: { + margin: 0, + padding: theme.spacing(2), + }, + closeButton: { + position: 'absolute', + right: theme.spacing(1), + top: theme.spacing(1), + color: theme.palette.grey[500], + }, + }); + +export interface PluginInfoDialogTitleProps extends WithStyles { + id: string; + children: React.ReactNode; + onClose: () => void; +} + +// const PluginInfoDialogTitle = withStyles(styles)((props: PluginInfoDialogTitleProps) => { +// const { children, classes, onClose, ...other } = props; +// return ( +// +//
+// +//
+//
+// {children} +//
+// handleClose()} +// style={{ flex: "0 0 auto" }}> +// +// +//
+// ); +// }); + +const PluginInfoDialogContent = withStyles((theme: Theme) => ({ + root: { + padding: theme.spacing(2), + }, +}))(MuiDialogContent); + +const PluginInfoDialogActions = withStyles((theme: Theme) => ({ + root: { + margin: 0, + padding: theme.spacing(1), + }, +}))(MuiDialogActions); + +export interface PluginInfoProps extends WithStyles { + plugin_uri: string +} + +function displayChannelCount(count: number): string { + if (count === 0) return "None"; + if (count === 1) return "Mono"; + if (count === 2) return "Stereo"; + return count + " channels"; +} +function ioDescription(plugin: UiPlugin): string { + let result = "Input: " + displayChannelCount(plugin.audio_inputs) + ". Output: " + displayChannelCount(plugin.audio_outputs) + "."; + if (plugin.has_midi_input) { + if (plugin.has_midi_output) { + result += " Midi in/out."; + } else { + result += " Midi in."; + } + } else { + if (plugin.has_midi_output) { + result += "Midi out."; + } + } + return result; + + +} + +function makeParagraphs(description: string) { + description = description.replaceAll('\r', ''); + description = description.replaceAll('\n\n', '\r'); + description = description.replaceAll('\n', ' '); + + let paragraphs: string[] = description.split('\r'); + return ( +
+ {paragraphs.map((para) => ( + + {para} + + ))} +
+ + ); +} +function makeControls(controls: UiControl[]) { + return ( + + { + controls.map((control) => ( + + + {control.name} + + + )) + } + + + ); + +} + +const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => { + + let model = PiPedalModelFactory.getInstance(); + const [open, setOpen] = React.useState(false); + let { classes, plugin_uri } = props; + + const handleClickOpen = () => { + setOpen(true); + }; + const handleClose = () => { + setOpen(false); + }; + let uri = props.plugin_uri; + let visible = true; + if (uri === null || uri === "") { + visible = false; + } + if (!visible) { + return (
); + }; + let plugin = model.getUiPlugin(plugin_uri); + + if (plugin === null) { + return (
) + } + + return ( +
+ + + + {open && ( + + +
+
+ +
+
+ {plugin.name} +
+ handleClose()} + style={{ flex: "0 0 auto" }}> + + +
+
+ + + Author:  + {(plugin.author_homepage !== "") + ? {plugin.author_name} + : ( + plugin.author_name + ) + } + + + {ioDescription(plugin)} + + + + Controls: + + { + makeControls(plugin.controls) + } + + Description: + + { + (plugin.description !== "") && makeParagraphs(plugin.description) + } + + + + +
+ )} +
+ ); +}); + +export default PluginInfoDialog; diff --git a/react/src/PluginPreset.tsx b/react/src/PluginPreset.tsx new file mode 100644 index 0000000..205a96d --- /dev/null +++ b/react/src/PluginPreset.tsx @@ -0,0 +1,20 @@ + + +export default class PluginPreset { + deserialize(input: any): PluginPreset { + this.presetUri = input.presetUri; + this.name = input.name; + return this; + } + static deserialize_array(input: any) : PluginPreset[] { + let result: PluginPreset[] = []; + for (let i = 0; i < input.length; ++i) + { + result.push(new PluginPreset().deserialize(input[i])); + } + return result; + } + + presetUri: string = ""; + name: string = ""; +} \ No newline at end of file diff --git a/react/src/PluginPresetSelector.tsx b/react/src/PluginPresetSelector.tsx new file mode 100644 index 0000000..28e18d9 --- /dev/null +++ b/react/src/PluginPresetSelector.tsx @@ -0,0 +1,284 @@ +import { SyntheticEvent, Component } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import PresetDialog from './PresetDialog'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import Fade from '@material-ui/core/Fade'; +import RenameDialog from './RenameDialog' +import PluginPreset from './PluginPreset'; + + +interface PluginPresetSelectorProps extends WithStyles { + pluginUri?: string; + + onSelectPreset: (presetName: string) => void; +}; + + +interface PluginPresetSelectorState { + presets: PluginPreset[] | null; + enabled: boolean; + showPresetsDialog: boolean; + showEditPresetsDialog: boolean; + presetsMenuAnchorRef: HTMLElement | null; + + renameDialogOpen: boolean; + renameDialogDefaultName: string; + renameDialogActionName: string; + renameDialogOnOk?: (name: string) => void; + +}; + + +const styles = (theme: Theme) => createStyles({ +}); + + +const PluginPresetSelector = + withStyles(styles, { withTheme: true })( + class extends Component { + + model: PiPedalModel; + + constructor(props: PluginPresetSelectorProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + presets: null, + enabled: false, + showPresetsDialog: false, + showEditPresetsDialog: false, + presetsMenuAnchorRef: null, + renameDialogOpen: false, + renameDialogDefaultName: "", + renameDialogActionName: "", + renameDialogOnOk: undefined + + }; + this.handleDialogClose = this.handleDialogClose.bind(this); + this.handlePresetsMenuClose = this.handlePresetsMenuClose.bind(this); + } + + handleLoadPluginPreset(presetName: string) + { + this.handlePresetsMenuClose(); + this.props.onSelectPreset(presetName); + } + + handlePresetMenuClick(e: SyntheticEvent): void { + this.setState({ presetsMenuAnchorRef: (e.currentTarget as HTMLElement) }); + } + handlePresetsMenuClose(): void { + this.setState({ presetsMenuAnchorRef: null }); + } + + handlePresetsMenuSave(e: SyntheticEvent): void { + this.handlePresetsMenuClose(); + e.stopPropagation(); + + this.model.saveCurrentPreset(); + } + handlePresetsMenuSaveAs(e: SyntheticEvent): void { + this.handlePresetsMenuClose(); + e.stopPropagation(); + + let currentPresets = this.model.presets.get(); + let item = currentPresets.getItem(currentPresets.selectedInstanceId); + if (item == null) return; + let name = item.name; + + this.renameDialogOpen(name, "Save As") + .then((newName) => { + return this.model.saveCurrentPresetAs(newName); + }) + .then((newInstanceId) => { + // s'fine. dealt with by updates, but we do need error handling. + }) + .catch((error) => { + this.showError(error); + }) + ; + } + + handlePresetsMenuRename(e: SyntheticEvent): void { + this.handlePresetsMenuClose(); + e.stopPropagation(); + + let currentPresets = this.model.presets.get(); + let item = currentPresets.getItem(currentPresets.selectedInstanceId); + if (item == null) return; + let name = item.name; + + this.renameDialogOpen(name, "Rename") + .then((newName) => { + if (newName === name) return; + return this.model.renamePresetItem(this.model.presets.get().selectedInstanceId, newName); + }) + .catch((error) => { + this.showError(error); + }) + ; + } + + showError(error: string) { + this.model.showAlert(error); + } + renameDialogOpen(defaultText: string, acceptButtonText: string): Promise { + let result = new Promise( + (resolve, reject) => { + this.setState( + { + renameDialogOpen: true, + renameDialogDefaultName: defaultText, + renameDialogActionName: acceptButtonText, + renameDialogOnOk: (name) => { + resolve(name); + } + + } + ); + + } + ); + return result; + } + + currentUri?: string = ""; + componentDidUpdate() + { + if (this.currentUri !== this.props.pluginUri) + { + this.currentUri = this.props.pluginUri; + if (!this.props.pluginUri) + { + this.setState({presets: null}); + } else { + this.setState({presets: null}); + let captureUri = this.currentUri; + this.model.getPluginPresets(this.props.pluginUri) + .then((presets: PluginPreset[]) => { + if (captureUri === this.currentUri) + { + this.setState({presets: presets}); + } + }) + .catch(error => { + if (captureUri === this.currentUri) + { + this.setState({presets: null}); + } + }); + } + } + } + handleRenameDialogClose(): void { + this.setState({ + renameDialogOpen: false, + renameDialogOnOk: undefined + }); + } + + handleRenameDialogOk(name: string): void { + let renameDialogOnOk = this.state.renameDialogOnOk; + this.handleRenameDialogClose(); + + if (renameDialogOnOk) { + renameDialogOnOk(name); + } + + } + + + handleMenuEditPresets(): void { + this.handlePresetsMenuClose(); + this.showEditPresetsDialog(true); + } + + handleSave() { + this.model.saveCurrentPreset(); + } + + showPresetDialog(show: boolean) { + this.setState({ + showPresetsDialog: show, + showEditPresetsDialog: false + }); + } + showEditPresetsDialog(show: boolean) { + this.setState({ + showPresetsDialog: show, + showEditPresetsDialog: true + }); + } + + handleDialogClose(): void { + this.showPresetDialog(false); + } + handleChange(event: any, extra: any): void { + // misses click on default. + // this.model.loadPreset(event.target.value as number); + } + handleSelectClose(event: any): void { + let value = event.currentTarget.getAttribute("data-value"); + if (value && value.length > 0) { + this.model.loadPreset(parseInt(value)); + } + //this.model.loadPreset(event.target.value as number); + } + + render() { + //let classes = this.props.classes; + //let classes = this.props.classes; + if ((!this.props.pluginUri) || (!this.state.presets) ||this.state.presets.length === 0) + { + return (
); + } + return ( +
+ this.handlePresetMenuClick(e)}> + Plugin Presets + + this.handlePresetsMenuClose()} + TransitionComponent={Fade} + MenuListProps={ + { + style: {minWidth: 180} + } + } + + > + Plugin presets + { + this.state.presets.map((preset) => { + return ( this.handleLoadPluginPreset(preset.presetUri)}>{preset.name}); + }) + } + {/* + + this.handlePresetsMenuSave(e)}>Save plugin preset + this.handlePresetsMenuSaveAs(e)}>Save plugin preset as... + this.handlePresetsMenuRename(e)}>Rename... + this.handleMenuEditPresets()}>Manage presets... + */} + + + this.handleDialogClose()} /> + this.handleRenameDialogClose()} + onOk={(name: string) => this.handleRenameDialogOk(name)} /> +
+ ) + + } + }); + +export default PluginPresetSelector; diff --git a/react/src/PresetDialog.tsx b/react/src/PresetDialog.tsx new file mode 100644 index 0000000..71c364b --- /dev/null +++ b/react/src/PresetDialog.tsx @@ -0,0 +1,450 @@ +import React, { SyntheticEvent,Component } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import { PiPedalModel, PiPedalModelFactory, PresetIndexEntry, PresetIndex } from './PiPedalModel'; +import Button from "@material-ui/core/Button"; +import ButtonBase from "@material-ui/core/ButtonBase"; +import { TransitionProps } from '@material-ui/core/transitions/transition'; +import Slide from '@material-ui/core/Slide'; +import Dialog from '@material-ui/core/Dialog'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import DraggableGrid, { ScrollDirection } from './DraggableGrid'; +import MoreVertIcon from '@material-ui/icons/MoreVert'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import Fade from '@material-ui/core/Fade'; +import UploadDialog from './UploadDialog'; + +import SelectHoverBackground from './SelectHoverBackground'; +import CloseIcon from '@material-ui/icons/Close'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import EditIcon from '@material-ui/icons/Edit'; +import RenameDialog from './RenameDialog'; + +interface PresetDialogProps extends WithStyles { + show: boolean; + isEditDialog: boolean; + onDialogClose: () => void; + +}; + +interface PresetDialogState { + presets: PresetIndex; + + showActionBar: boolean; + + selectedItem: number; + + renameOpen: boolean; + + moreMenuAnchorEl: HTMLElement | null; + openUploadDialog: boolean; + + +}; + + +const styles = (theme: Theme) => createStyles({ + dialogAppBar: { + position: 'relative', + top: 0, left: 0 + }, + dialogActionBar: { + position: 'relative', + top: 0, left: 0, + background: "black" + }, + dialogTitle: { + marginLeft: theme.spacing(2), + flex: 1, + }, + itemFrame: { + display: "flex", + flexDirection: "row", + flexWrap: "nowrap", + width: "100%", + height: "56px", + alignItems: "center", + textAlign: "left", + justifyContent: "center", + paddingLeft: 8 + }, + iconFrame: { + flex: "0 0 auto", + + }, + itemIcon: { + width: 24, height: 24, margin: 12, opacity: 0.6 + }, + itemLabel: { + flex: "1 1 1px", + marginLeft: 8 + } + +}); + + +const Transition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const ActionBarTransition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + + +const PresetDialog = withStyles(styles, { withTheme: true })( + + class extends Component { + + model: PiPedalModel; + + + + constructor(props: PresetDialogProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.handleDialogClose = this.handleDialogClose.bind(this); + let presets = this.model.presets.get(); + this.state = { + presets: presets, + showActionBar: false, + selectedItem: presets.selectedInstanceId, + renameOpen: false, + moreMenuAnchorEl: null, + openUploadDialog: false + + }; + this.handlePresetsChanged = this.handlePresetsChanged.bind(this); + + } + + selectItemAtIndex(index: number) { + let instanceId = this.state.presets.presets[index].instanceId; + this.setState({ selectedItem: instanceId }); + } + isEditMode() { + return this.state.showActionBar || this.props.isEditDialog; + } + + onMoreClick(e: SyntheticEvent): void { + this.setState({ moreMenuAnchorEl: e.currentTarget as HTMLElement }) + } + + handleDownloadPreset() { + this.handleMoreClose(); + this.model.download("downloadPreset", this.model.presets.get().selectedInstanceId); + } + handleUploadPreset() { + this.handleMoreClose(); + this.setState({ openUploadDialog: true }); + + } + handleMoreClose(): void { + this.setState({ moreMenuAnchorEl: null }); + + } + + + handlePresetsChanged() { + let presets = this.model.presets.get(); + + if (!presets.areEqual(this.state.presets, false)) // avoid a bunch of peculiar effects if we update while a drag is in progress + { + // if we don't have a valid selection, then use the current preset. + if (this.state.presets.getItem(this.state.selectedItem) == null) { + this.setState({ presets: presets, selectedItem: presets.selectedInstanceId }); + } else { + this.setState({ presets: presets }); + } + } + } + + + componentDidMount() { + this.model.presets.addOnChangedHandler(this.handlePresetsChanged); + this.handlePresetsChanged(); + // scroll selected item into view. + } + componentWillUnmount() { + this.model.presets.removeOnChangedHandler(this.handlePresetsChanged); + } + + getSelectedIndex() { + let instanceId = this.isEditMode() ? this.state.selectedItem : this.state.presets.selectedInstanceId; + let presets = this.state.presets; + for (let i = 0; i < presets.presets.length; ++i) { + if (presets.presets[i].instanceId === instanceId) return i; + } + return -1; + } + + handleDeleteClick() { + if (!this.state.selectedItem) return; + let selectedItem = this.state.selectedItem; + if (selectedItem !== -1) { + this.model.deletePresetItem(selectedItem) + .then((selectedItem: number) => { + this.setState({ selectedItem: selectedItem }); + }) + .catch((error) => { + this.model.showAlert(error); + }); + + } + } + handleDialogClose() { + this.props.onDialogClose(); + } + + handleItemClick(instanceId: number): void { + if (this.isEditMode()) { + this.setState({ selectedItem: instanceId }); + } else { + this.model.loadPreset(instanceId); + this.props.onDialogClose(); + } + } + showActionBar(show: boolean): void { + this.setState({ showActionBar: show }); + + } + + + mapElement(el: any): React.ReactNode { + let presetEntry = el as PresetIndexEntry; + let classes = this.props.classes; + let selectedItem = this.isEditMode() ? this.state.selectedItem : this.state.presets.selectedInstanceId; + return ( +
+ + this.handleItemClick(presetEntry.instanceId)} + > + +
+
+ +
+
+ + {presetEntry.name} + +
+
+
+
+ + ); + } + + updateServerPresets(newPresets: PresetIndex) { + newPresets = newPresets.clone(); + this.model.updatePresets(newPresets) + .catch((error) => { + this.model.showAlert(error); + }); + } + moveElement(from: number, to: number): void { + let newPresets = this.state.presets.clone(); + newPresets.movePreset(from, to); + this.setState({ + presets: newPresets, + selectedItem: newPresets.presets[to].instanceId + }); + this.updateServerPresets(newPresets); + } + + getSelectedName(): string { + let item = this.state.presets.getItem(this.state.selectedItem); + if (item) return item.name; + return ""; + } + + handleRenameClick() { + let item = this.state.presets.getItem(this.state.selectedItem); + if (item) { + this.setState({ renameOpen: true }); + } + } + handleRenameOk(text: string) { + let item = this.state.presets.getItem(this.state.selectedItem); + if (!item) return; + if (item.name !== text) { + this.model.renamePresetItem(this.state.selectedItem, text) + .catch((error) => { + this.onError(error); + }); + } + + this.setState({ renameOpen: false }); + } + handleCopy() { + let item = this.state.presets.getItem(this.state.selectedItem); + if (!item) return; + this.model.duplicatePreset(this.state.selectedItem) + .then((newId) => { + this.setState({ selectedItem: newId }); + }).catch((error) => { + this.onError(error); + }); + } + + onError(error: string): void { + this.model?.showAlert(error); + } + + + + render() { + let classes = this.props.classes; + + let actionBarClass = this.props.isEditDialog ? classes.dialogAppBar : classes.dialogActionBar; + let defaultSelectedIndex = this.getSelectedIndex(); + + return ( + { this.handleDialogClose() }} TransitionComponent={Transition}> +
+
+ + + + + + + Presets + + this.showActionBar(true)} > + + + + + { e.stopPropagation(); e.preventDefault(); }} + > + + {(!this.props.isEditDialog) ? ( + this.showActionBar(false)} aria-label="close"> + + + ) : ( + + + + + )} + + Presets + + {(this.state.presets.getItem(this.state.selectedItem) != null) + && ( + +
+ + + { this.setState({ renameOpen: false }) }} + onOk={(text: string) => { + this.handleRenameOk(text); + } + } + /> + this.handleDeleteClick()} > + Delete + + { this.onMoreClick(e) }} > + + + this.handleMoreClose()} + TransitionComponent={Fade} + > + { this.handleDownloadPreset(); }} > + + + + + Download preset + + + + { this.handleUploadPreset() }}> + + + + + Upload preset + + + + + + +
+ ) + } +
+ +
+
+
+ this.showActionBar(true)} + canDrag={this.isEditMode()} + onDragStart={(index, x, y) => { this.selectItemAtIndex(index) }} + moveElement={(from, to) => { this.moveElement(from, to); }} + scroll={ScrollDirection.Y} + defaultSelectedIndex={defaultSelectedIndex} + > + { + this.state.presets.presets.map((element) => { + return this.mapElement(element); + }) + } + +
+
+ this.setState({selectedItem: instanceId}) } + uploadAfter={this.state.selectedItem} + open={this.state.openUploadDialog} + onClose={() => { this.setState({ openUploadDialog: false }) }} /> + +
+ + ); + + } + + } + +); + +export default PresetDialog; \ No newline at end of file diff --git a/react/src/PresetSelector.tsx b/react/src/PresetSelector.tsx new file mode 100644 index 0000000..ab642c2 --- /dev/null +++ b/react/src/PresetSelector.tsx @@ -0,0 +1,355 @@ +import { SyntheticEvent, Component } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import { PiPedalModel, PiPedalModelFactory, PresetIndex } from './PiPedalModel'; +import SaveIconOutline from '@material-ui/icons/Save'; +import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; +import ButtonBase from "@material-ui/core/ButtonBase"; +import MoreVertIcon from '@material-ui/icons/MoreVert'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import PresetDialog from './PresetDialog'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import Fade from '@material-ui/core/Fade'; +import Divider from '@material-ui/core/Divider'; +import RenameDialog from './RenameDialog' +import Select from '@material-ui/core/Select'; +import UploadDialog from './UploadDialog'; + + +interface PresetSelectorProps extends WithStyles { + +}; + + +interface PresetSelectorState { + presets: PresetIndex; + enabled: boolean; + showPresetsDialog: boolean; + showEditPresetsDialog: boolean; + presetsMenuAnchorRef: HTMLElement | null; + + renameDialogOpen: boolean; + renameDialogDefaultName: string; + renameDialogActionName: string; + renameDialogOnOk?: (name: string) => void; + openUploadDialog: boolean; + +}; + + +const selectColor = "white"; + +const styles = (theme: Theme) => createStyles({ + select: { // fu fu fu.Overrides for white selector on dark background. + '&:before': { + borderColor: selectColor, + }, + '&:after': { + borderColor: selectColor, + }, + '&:hover:not(.Mui-disabled):before': { + borderColor: selectColor, + } + }, + icon: { + fill: selectColor, + }, +}); + + +const PresetSelector = + withStyles(styles, { withTheme: true })( + class extends Component { + + model: PiPedalModel; + + constructor(props: PresetSelectorProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + presets: + this.model.presets.get(), + enabled: false, + showPresetsDialog: false, + showEditPresetsDialog: false, + presetsMenuAnchorRef: null, + renameDialogOpen: false, + renameDialogDefaultName: "", + renameDialogActionName: "", + renameDialogOnOk: undefined, + openUploadDialog: false + + + }; + this.handlePresetsChanged = this.handlePresetsChanged.bind(this); + this.handleDialogClose = this.handleDialogClose.bind(this); + this.handlePresetsMenuClose = this.handlePresetsMenuClose.bind(this); + } + + + handlePresetMenuClick(event: SyntheticEvent): void { + this.setState({ presetsMenuAnchorRef: (event.currentTarget as HTMLElement) }); + } + handlePresetsMenuClose(): void { + this.setState({ presetsMenuAnchorRef: null }); + } + + handleDownloadPreset(e: SyntheticEvent) { + this.handlePresetsMenuClose(); + e.preventDefault(); + + this.model.download("downloadPreset", this.model.presets.get().selectedInstanceId); + } + handleUploadPreset(e: SyntheticEvent) { + this.handlePresetsMenuClose(); + e.preventDefault(); + + this.setState({ openUploadDialog: true }); + + } + + handlePresetsMenuSave(e: SyntheticEvent): void { + this.handlePresetsMenuClose(); + e.preventDefault(); + + this.model.saveCurrentPreset(); + } + handlePresetsMenuSaveAs(e: SyntheticEvent): void { + this.handlePresetsMenuClose(); + e.stopPropagation(); + + let currentPresets = this.model.presets.get(); + let item = currentPresets.getItem(currentPresets.selectedInstanceId); + if (item == null) return; + let name = item.name; + + this.renameDialogOpen(name, "Save As") + .then((newName) => { + return this.model.saveCurrentPresetAs(newName); + }) + .then((newInstanceId) => { + // s'fine. dealt with by updates, but we do need error handling. + }) + .catch((error) => { + this.showError(error); + }) + ; + + + } + handlePresetsMenuRename(e: SyntheticEvent): void { + this.handlePresetsMenuClose(); + e.stopPropagation(); + + let currentPresets = this.model.presets.get(); + let item = currentPresets.getItem(currentPresets.selectedInstanceId); + if (item == null) return; + let name = item.name; + + this.renameDialogOpen(name, "Rename") + .then((newName) => { + if (newName === name) return; + return this.model.renamePresetItem(this.model.presets.get().selectedInstanceId, newName); + }) + .catch((error) => { + this.showError(error); + }) + ; + } + + showError(error: string) { + this.model.showAlert(error); + } + renameDialogOpen(defaultText: string, acceptButtonText: string): Promise { + let result = new Promise( + (resolve, reject) => { + this.setState( + { + renameDialogOpen: true, + renameDialogDefaultName: defaultText, + renameDialogActionName: acceptButtonText, + renameDialogOnOk: (name) => { + resolve(name); + } + + } + ); + + } + ); + return result; + } + + handleRenameDialogClose(): void { + this.setState({ + renameDialogOpen: false, + renameDialogOnOk: undefined + }); + } + + handleRenameDialogOk(name: string): void { + let renameDialogOnOk = this.state.renameDialogOnOk; + this.handleRenameDialogClose(); + + if (renameDialogOnOk) { + renameDialogOnOk(name); + } + + } + + + handleMenuEditPresets(): void { + this.handlePresetsMenuClose(); + this.showEditPresetsDialog(true); + } + + updatePresetState() { + let presets = this.model.presets.get(); + let enabled = presets.presets.length > 0 && presets.selectedInstanceId !== -1; + this.setState( + { + presets: presets, + enabled: enabled, + } + ); + } + handleSave() { + this.model.saveCurrentPreset(); + } + handlePresetsChanged() { + this.updatePresetState(); + } + componentDidMount() { + this.model.presets.addOnChangedHandler(this.handlePresetsChanged); + this.updatePresetState(); + } + componentWillUnmount() { + this.model.presets.removeOnChangedHandler(this.handlePresetsChanged) + } + showPresetDialog(show: boolean) { + this.setState({ + showPresetsDialog: show, + showEditPresetsDialog: false + }); + } + showEditPresetsDialog(show: boolean) { + this.setState({ + showPresetsDialog: show, + showEditPresetsDialog: true + }); + } + + handleDialogClose(): void { + this.showPresetDialog(false); + } + handleChange(event: any, extra: any): void { + // misses click on default. + // this.model.loadPreset(event.target.value as number); + } + handleSelectClose(event: any): void { + let value = event.currentTarget.getAttribute("data-value"); + if (value && value.length > 0) { + this.model.loadPreset(parseInt(value)); + } + //this.model.loadPreset(event.target.value as number); + } + + render() { + //let classes = this.props.classes; + let presets = this.state.presets; + let classes = this.props.classes; + return ( +
+
+ {true ? ( + + ) : ( + { this.showPresetDialog(true); }} + > +
+
+ + {this.state.presets.getSelectedText()} + +
+
+
+ +
+ +
+ + )} +
+
+ { this.handleSave(); }} > + + +
+
+ this.handlePresetMenuClick(e)}> + + + this.handlePresetsMenuClose()} + TransitionComponent={Fade} + > + this.handlePresetsMenuSave(e)}>Save preset + this.handlePresetsMenuSaveAs(e)}>Save preset as... + this.handlePresetsMenuRename(e)}>Rename... + + { this.handleDownloadPreset(e); }} >Download preset + { this.handleUploadPreset(e) }}>Upload preset + + this.handleMenuEditPresets()}>Manage presets... + +
+ this.handleDialogClose()} /> + this.handleRenameDialogClose()} + onOk={(name: string) => this.handleRenameDialogOk(name)} /> + { this.model.loadPreset(instanceId); }} + open={this.state.openUploadDialog} + uploadAfter={-1} + onClose={() => { this.setState({ openUploadDialog: false }) }} /> + +
+ ) + + } + }); + +export default PresetSelector; \ No newline at end of file diff --git a/react/src/Rect.tsx b/react/src/Rect.tsx new file mode 100644 index 0000000..0322526 --- /dev/null +++ b/react/src/Rect.tsx @@ -0,0 +1,70 @@ +const LARGE_NUMBER = 0x1FFFFFFF; +const EMPTY_WIDTH = -LARGE_NUMBER * 2; + +class Rect { + x: number; + y: number; + width: number; + height: number; + + constructor(x: number = LARGE_NUMBER, y: number = LARGE_NUMBER, width: number = EMPTY_WIDTH, height: number = EMPTY_WIDTH) + { + this.x = x; this.y = y; this.width = width; this.height = height; + } + + toString() { return '{' + this.x + "," + this.y + " " + this.width + "," + this.height +"}"; } + copy(): Rect { + let result = new Rect(); + result.x = this.x; + result.y = this.y; + result.width = this.width; + result.height = this.height; + return result; + + } + contains(x: number, y: number) + { + return (x >= this.x) + && x < this.x+this.width + && y >= this.y + && y < this.y + this.height; + } + get right(): number { + return this.x + this.width; + } + get bottom(): number { + return this.y + this.height; + } + isEmpty(): boolean { + return this.width === 0 || this.height === 0; + } + clear(): void { + this.x = LARGE_NUMBER; + this.y = LARGE_NUMBER; + this.width = EMPTY_WIDTH; + this.height = EMPTY_WIDTH; + + } + accumulate(rect: Rect): void { + let right = Math.max(rect.x + rect.width, this.x + this.width); + let bottom = Math.max(rect.y + rect.height, this.y + this.height); + this.x = Math.min(rect.x, this.x); + this.y = Math.min(rect.y, this.y); + this.width = right - this.x; + this.height = bottom - this.y; + } + union(rect: Rect): Rect { + let result = new Rect(); + result.x = Math.min(this.x, rect.x); + result.y = Math.min(this.y, rect.y); + result.width = Math.max(this.x + this.width, rect.x + rect.width) - result.x; + result.height = Math.max(this.y + this.height, rect.x + rect.height) - result.y; + return result; + } + offset(xOffset: number, yOffset: number) { + this.x += xOffset; + this.y += yOffset; + } +} + +export default Rect; \ No newline at end of file diff --git a/react/src/RenameDialog.tsx b/react/src/RenameDialog.tsx new file mode 100644 index 0000000..880bf82 --- /dev/null +++ b/react/src/RenameDialog.tsx @@ -0,0 +1,156 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import TextField from '@material-ui/core/TextField'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import { nullCast } from './Utility'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; + + +export interface RenameDialogProps { + open: boolean, + defaultName: string, + acceptActionName: string, + onOk: (text: string) => void, + onClose: () => void +}; + +export interface RenameDialogState { + fullScreen: boolean; +}; + +export default class RenameDialog extends ResizeResponsiveComponent { + + refText: React.RefObject; + + constructor(props: RenameDialogProps) { + super(props); + this.state = { + fullScreen: false + }; + this.refText = React.createRef(); + this.handlePopState = this.handlePopState.bind(this); + } + mounted: boolean = false; + + hasHooks: boolean = false; + + stateWasPopped: boolean = false; + handlePopState(e: any): any { + this.stateWasPopped = true; + let shouldClose = (!e.state || !e.state.renameDialog); + if (shouldClose) + { + this.props.onClose(); + } + } + + updateHooks() : void { + let wantHooks = this.mounted && this.props.open; + if (wantHooks !== this.hasHooks) + { + this.hasHooks = wantHooks; + + if (this.hasHooks) + { + this.stateWasPopped = false; + window.addEventListener("popstate",this.handlePopState); + // eslint-disable-next-line no-restricted-globals + let state = history.state; + if (!state) + { + state = {}; + } + state.renameDialog = true; + + // eslint-disable-next-line no-restricted-globals + history.pushState( + state, + this.props.acceptActionName, + "#RenameDialog" + ); + } else { + window.removeEventListener("popstate",this.handlePopState); + if (!this.stateWasPopped) + { + // eslint-disable-next-line no-restricted-globals + history.back(); + } + } + + } + } + onWindowSizeChanged(width: number, height: number): void + { + this.setState({fullScreen: height < 200}) + } + + + componentDidMount() + { + super.componentDidMount(); + this.mounted = true; + this.updateHooks(); + } + componentWillUnmount() + { + super.componentDidMount(); + this.mounted = false; + this.updateHooks(); + } + + componentDidUpdate() + { + this.updateHooks(); + } + + render() { + let props = this.props; + let { open, defaultName, acceptActionName, onClose, onOk } = props; + + const handleClose = () => { + onClose(); + }; + + const handleOk = () => { + let text = nullCast(this.refText.current).value; + onOk(text); + } + const handleKeyDown = (event: React.KeyboardEvent): void => { + // 'keypress' event misbehaves on mobile so we track 'Enter' key via 'keydown' event + if (event.key === 'Enter') { + event.preventDefault(); + event.stopPropagation(); + handleOk(); + } + }; + return ( + + + + + + + + + + ); + } +} \ No newline at end of file diff --git a/react/src/ResizeResponsiveComponent.tsx b/react/src/ResizeResponsiveComponent.tsx new file mode 100644 index 0000000..e731f38 --- /dev/null +++ b/react/src/ResizeResponsiveComponent.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + + +class ResizeResponsiveComponent extends React.Component { + constructor(props: PROPS) { + super(props); + this.handleWindowResize = this.handleWindowResize.bind(this); + this.windowSize.width = window.innerWidth; + this.windowSize.height = window.innerHeight; + } + + windowSize: {width: number,height:number} = {width: 1280, height: 1024}; + + onWindowSizeChanged(width: number, height: number): void { + + } + handleWindowResize() { + let width_ = window.innerWidth; + let height_ = window.innerHeight; + if (width_ !== this.windowSize.width || height_ !== this.windowSize.height) + { + this.windowSize = {width: width_, height: height_}; + this.onWindowSizeChanged(this.windowSize.width,this.windowSize.height); + + + } + } + + + componentDidMount() { + window.addEventListener('resize', this.handleWindowResize); + + let width_ = window.innerWidth; + let height_ = window.innerHeight; + this.windowSize = {width: width_, height: height_}; + this.onWindowSizeChanged(this.windowSize.width,this.windowSize.height); + } + componentWillUnmount() { + window.removeEventListener('resize', this.handleWindowResize); + } + +} + +export default ResizeResponsiveComponent; \ No newline at end of file diff --git a/react/src/SelectChannelsDialog.tsx b/react/src/SelectChannelsDialog.tsx new file mode 100644 index 0000000..48b3bae --- /dev/null +++ b/react/src/SelectChannelsDialog.tsx @@ -0,0 +1,154 @@ +import { useState } from 'react'; +import Button from '@material-ui/core/Button'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemText from '@material-ui/core/ListItemText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogActions from '@material-ui/core/DialogActions'; +import Dialog from '@material-ui/core/Dialog'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; + +import Checkbox from '@material-ui/core/Checkbox'; + + + +export interface SelectChannelsDialogProps { + open: boolean; + selectedChannels: string[]; + availableChannels: string[]; + onClose: (selectedChannels: string[] | null) => void; +} + +function isChecked(selectedChannels: string[], channel: string): boolean { + for (let i = 0; i < selectedChannels.length; ++i) { + if (selectedChannels[i] === channel) return true; + } + return false; +} +function addPort(availableChannels: string[], selectedChannels: string[], newChannel: string) { + let result: string[] = []; + for (let i = 0; i < availableChannels.length; ++i) { + let channel = availableChannels[i]; + if (isChecked(selectedChannels, channel) || channel === newChannel) { + result.push(channel); + } + } + return result; +} + +function removePort(selectedChannels: string[], channel: string) { + let result: string[] = []; + for (let i = 0; i < selectedChannels.length; ++i) { + if (selectedChannels[i] !== channel) { + result.push(selectedChannels[i]); + } + } + return result; +} + +function SelectChannelsDialog(props: SelectChannelsDialogProps) { + //const classes = useStyles(); + const { onClose, selectedChannels, availableChannels, open } = props; + const [currentSelection, setCurrentSelection] = useState(selectedChannels); + + + let showCheckboxes = availableChannels.length > 2; + if (showCheckboxes) { + + let toggleSelect = (value: string) => { + if (!isChecked(currentSelection, value)) { + setCurrentSelection(addPort(availableChannels, currentSelection, value)); + } else { + setCurrentSelection(removePort(currentSelection, value)); + } + }; + + const handleClose = (): void => { + onClose(null); + }; + const handleOk = (): void => { + onClose(currentSelection); + }; + + + return ( + + Select Channels + + {availableChannels.map((channel) => ( + + toggleSelect(channel)} key={channel} /> + } + label={channel} + /> + + ) + + )} + + + + + + + ); + + } else { + + const handleClose = () => { + onClose(selectedChannels); + }; + + const handleListItemClick = (value: string) => { + switch (value) { + case "Stereo": + onClose(availableChannels); + break; + case "Left": + onClose([availableChannels[0]]); + break; + case "Right": + onClose([availableChannels[1]]); + break; + case "None": + default: + onClose([availableChannels[1]]); + } + }; + let selectionKey = "None"; + if (currentSelection.length === 2) { + selectionKey = "Stereo"; + } else if (currentSelection.length === 1) { + if (currentSelection[0] === availableChannels[0]) { + selectionKey = "Left"; + } else { + selectionKey = "Right"; + } + } + + return ( + + + + handleListItemClick("Stereo")} key={"Stereo"} selected={selectionKey === "Stereo"} > + + + handleListItemClick("Left")} key={"LeftChannel"} selected={selectionKey === "Left"} > + + + handleListItemClick("Right")} key={"RightChannel"} selected={selectionKey === "Right"}> + + + + + ); + } +} + +export default SelectChannelsDialog; diff --git a/react/src/SelectHoverBackground.tsx b/react/src/SelectHoverBackground.tsx new file mode 100644 index 0000000..6955ced --- /dev/null +++ b/react/src/SelectHoverBackground.tsx @@ -0,0 +1,95 @@ +import { Component, SyntheticEvent } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; + + +const styles = ({ palette }: Theme) => createStyles({ + frame: { + position: "absolute", + width: "100%", + height: "100%" + }, + hover: { + position: "absolute", + width: "100%", + height: "100%", + background: "#000000", + opacity: 0.1 + }, + selected: { + position: "absolute", + width: "100%", + height: "100%", + background: palette.action.active, + opacity: 0.3 + } + +}); + + + +interface HoverProps extends WithStyles { + selected: boolean; + showHover?: boolean; + theme: Theme; +}; + +interface HoverState { + hovering: boolean; +}; + + +export const SelectHoverBackground = + withStyles(styles, { withTheme: true })( + class extends Component + { + constructor(props: HoverProps) { + super(props); + this.state = { + hovering: false + }; + + this.handleMouseEnter = this.handleMouseEnter.bind(this); + this.handleMouseLeave = this.handleMouseLeave.bind(this); + + } + + handleMouseEnter(e: SyntheticEvent): void { + if (this.props.showHover??true) + { + this.setHovering(true); + } + + } + handleMouseLeave(e: SyntheticEvent): void { + if (this.props.showHover??true) + { + this.setHovering(false); + } + + } + + + setHovering(value: boolean): void { + if (this.state.hovering !== value) { + this.setState({ hovering: value }); + } + } + render() { + let classes = this.props.classes; + let isSelected = this.props.selected; + let hovering = this.state.hovering && (this.props.showHover??true); + return (
{ this.handleMouseEnter(e); }} onMouseLeave={(e) => { this.handleMouseLeave(e) }} + > +
+
+
); + + } + } + ); + +export default SelectHoverBackground; + + + diff --git a/react/src/SelectMidiChannelsDialog.tsx b/react/src/SelectMidiChannelsDialog.tsx new file mode 100644 index 0000000..b93d084 --- /dev/null +++ b/react/src/SelectMidiChannelsDialog.tsx @@ -0,0 +1,101 @@ +import { useState } from 'react'; +import Button from '@material-ui/core/Button'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogActions from '@material-ui/core/DialogActions'; +import Dialog from '@material-ui/core/Dialog'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; + +import Checkbox from '@material-ui/core/Checkbox'; + + + + +export interface SelectMidiChannelsDialogProps { + open: boolean; + selectedChannels: string[]; + availableChannels: string[]; + onClose: (selectedChannels: string[] | null) => void; +} + +function isChecked(selectedChannels: string[], channel: string): boolean { + for (let i = 0; i < selectedChannels.length; ++i) { + if (selectedChannels[i] === channel) return true; + } + return false; +} +function addPort(availableChannels: string[], selectedChannels: string[], newChannel: string) { + let result: string[] = []; + for (let i = 0; i < availableChannels.length; ++i) { + let channel = availableChannels[i]; + if (isChecked(selectedChannels, channel) || channel === newChannel) { + result.push(channel); + } + } + return result; +} + +function removePort(selectedChannels: string[], channel: string) { + let result: string[] = []; + for (let i = 0; i < selectedChannels.length; ++i) { + if (selectedChannels[i] !== channel) { + result.push(selectedChannels[i]); + } + } + return result; +} + +function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) { + //const classes = useStyles(); + const { onClose, selectedChannels, availableChannels, open } = props; + const [currentSelection, setCurrentSelection] = useState(selectedChannels); + + + + let toggleSelect = (value: string) => { + if (!isChecked(currentSelection, value)) { + setCurrentSelection(addPort(availableChannels, currentSelection, value)); + } else { + setCurrentSelection(removePort(currentSelection, value)); + } + }; + + const handleClose = (): void => { + onClose(null); + }; + const handleOk = (): void => { + onClose(currentSelection); + }; + + + return ( + + Select Channels + + {availableChannels.map((channel) => ( + + toggleSelect(channel)} key={channel} /> + } + label={channel} + /> + + ) + + )} + + + + + + + ); +} + +export default SelectMidiChannelsDialog; diff --git a/react/src/SettingsDialog.tsx b/react/src/SettingsDialog.tsx new file mode 100644 index 0000000..350cc31 --- /dev/null +++ b/react/src/SettingsDialog.tsx @@ -0,0 +1,497 @@ +import React, { SyntheticEvent, Component } from 'react'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import ButtonBase from "@material-ui/core/ButtonBase"; +import { TransitionProps } from '@material-ui/core/transitions/transition'; +import Slide from '@material-ui/core/Slide'; +import Dialog from '@material-ui/core/Dialog'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import { Theme, withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import JackConfiguration, { JackChannelSelection } from './Jack'; +import Divider from '@material-ui/core/Divider'; +import SelectChannelsDialog from './SelectChannelsDialog'; +import SelectMidiChannelsDialog from './SelectMidiChannelsDialog'; +import SelectHoverBackground from './SelectHoverBackground'; +import JackServerSettings from './JackServerSettings'; +import JackServerSettingsDialog from './JackServerSettingsDialog'; +import JackHostStatus from './JackHostStatus'; + + + +interface SettingsDialogProps extends WithStyles { + open: boolean; + onClose: () => void; + + +}; + +interface SettingsDialogState { + jackConfiguration: JackConfiguration; + jackSettings: JackChannelSelection; + jackServerSettings: JackServerSettings; + jackStatus?: JackHostStatus; + + showInputSelectDialog: boolean; + showOutputSelectDialog: boolean; + showMidiSelectDialog: boolean; + showJackServerSettingsDialog: boolean; + shuttingDown: boolean; + restarting: boolean; +}; + + +const styles = (theme: Theme) => createStyles({ + dialogAppBar: { + position: 'relative', + top: 0, left: 0 + }, + dialogTitle: { + marginLeft: theme.spacing(2), + flex: 1, + }, + sectionHead: { + marginLeft: 24, + marginRight: 24, + marginTop: 16, + paddingBottom: 12 + + }, + textBlock: { + marginLeft: 24, + marginRight: 24, + marginTop: 16, + paddingBottom: 0, + opacity: 0.95 + + }, + textBlockIndented: { + marginLeft: 40, + marginRight: 24, + marginTop: 16, + paddingBottom: 0, + opacity: 0.95 + + }, + + setting: { + minHeight: 64, + width: "100%", + textAlign: "left", + paddingLeft: 22, + paddingRight: 22 + }, + primaryItem: { + + }, + secondaryItem: { + + } + + +}); + + +const Transition = React.forwardRef(function Transition( + props: TransitionProps & { children?: React.ReactElement }, + ref: React.Ref, +) { + return ; +}); + + +const SettingsDialog = withStyles(styles, { withTheme: true })( + + class extends Component { + + model: PiPedalModel; + + + + constructor(props: SettingsDialogProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.handleDialogClose = this.handleDialogClose.bind(this); + this.state = { + jackServerSettings: this.model.jackServerSettings.get(), + jackConfiguration: this.model.jackConfiguration.get(), + jackStatus: undefined, + jackSettings: this.model.jackSettings.get(), + showInputSelectDialog: false, + showOutputSelectDialog: false, + showMidiSelectDialog: false, + showJackServerSettingsDialog: false, + shuttingDown: false, + restarting: false + + + }; + this.handleJackConfigurationChanged = this.handleJackConfigurationChanged.bind(this); + this.handleJackSettingsChanged = this.handleJackSettingsChanged.bind(this); + this.handleJackServerSettingsChanged = this.handleJackServerSettingsChanged.bind(this); + + } + + + handleJackSettingsChanged(): void { + this.setState({ + jackSettings: this.model.jackSettings.get() + }); + } + handleJackServerSettingsChanged(): void { + this.setState({ + jackServerSettings: this.model.jackServerSettings.get() + }); + } + + handleJackConfigurationChanged(): void { + this.setState({ + jackConfiguration: this.model.jackConfiguration.get() + }); + } + + mounted: boolean = false; + active: boolean = false; + + timerHandle?: NodeJS.Timeout; + + tick() { + this.model.getJackStatus() + .then((jackStatus) => + this.setState( + { + jackStatus: jackStatus + }) + ) + .catch((error) => { }); + } + + updateActive() { + let active = this.mounted && this.props.open; + if (active !== this.active) { + this.active = active; + if (active) { + this.model.jackSettings.addOnChangedHandler(this.handleJackSettingsChanged); + this.model.jackConfiguration.addOnChangedHandler(this.handleJackConfigurationChanged); + this.model.jackServerSettings.addOnChangedHandler(this.handleJackServerSettingsChanged); + this.model.getJackStatus() + .then((jackStatus) => + this.setState( + { + jackStatus: jackStatus + }) + ) + .catch((error) => { + this.setState( + { + jackStatus: undefined + }) + }); + this.handleJackConfigurationChanged(); + this.handleJackSettingsChanged(); + this.handleJackServerSettingsChanged(); + this.timerHandle = setInterval(() => this.tick(), 1000); + } else { + if (this.timerHandle) { + clearInterval(this.timerHandle); + } + this.model.jackConfiguration.removeOnChangedHandler(this.handleJackConfigurationChanged); + this.model.jackSettings.removeOnChangedHandler(this.handleJackSettingsChanged); + this.model.jackServerSettings.removeOnChangedHandler(this.handleJackServerSettingsChanged); + } + } + + } + + componentDidMount() { + this.mounted = true; + this.updateActive(); + // scroll selected item into view. + } + componentDidUpdate() { + this.updateActive(); + } + componentWillUnmount() { + this.mounted = false; + this.updateActive(); + } + + handleDialogClose(e: SyntheticEvent) { + this.props.onClose(); + } + + handleMidiSelection() { + this.setState({ + showMidiSelectDialog: true + }) + } + handleJackServerSettings() { + this.setState({ + showJackServerSettingsDialog: true, + }); + } + + handleInputSelection() { + this.setState({ + showInputSelectDialog: true, + showOutputSelectDialog: false + }); + } + + handleOutputSelection() { + this.setState({ + showInputSelectDialog: false, + showOutputSelectDialog: true + }); + + } + handleSelectMidiDialogResult(channels: string[] | null): void { + if (channels) { + let newSelection = this.state.jackSettings.clone(); + newSelection.inputMidiPorts = channels; + this.model.setJackSettings(newSelection); + } + this.setState({ + showMidiSelectDialog: false, + + }); + + } + + handleSelectChannelsDialogResult(channels: string[] | null): void { + if (channels) { + let newSelection = this.state.jackSettings.clone(); + if (this.state.showInputSelectDialog) { + newSelection.inputAudioPorts = channels; + } else { + newSelection.outputAudioPorts = channels; + } + this.setState({ + jackSettings: newSelection, + showInputSelectDialog: false, + showOutputSelectDialog: false + + }); + this.model.setJackSettings(newSelection); + } else { + this.setState({ + showInputSelectDialog: false, + showOutputSelectDialog: false + + }); + + } + } + + midiSummary(): string { + let ports = this.state.jackSettings.inputMidiPorts; + if (ports.length === 0) return "Disabled"; + if (ports.length === 1) return ports[0]; + return ports.length + " channels"; + } + + handleRestart() { + this.model.restart() + .then(() => { + this.setState({ restarting: true }); + }) + .catch((error) => { + this.model.showAlert(error); + }); + + } + + handleShutdown() { + this.model.shutdown() + .then(() => { + this.setState({ shuttingDown: true }); + }) + .catch((error) => { + this.model.showAlert(error); + }); + + } + + render() { + let classes = this.props.classes; + let isConfigValid = this.state.jackConfiguration.isValid; + let selectedChannels: string[] = this.state.showInputSelectDialog ? this.state.jackSettings.inputAudioPorts : this.state.jackSettings.outputAudioPorts; + let disableShutdown = this.state.shuttingDown || this.state.restarting; + + return ( + { this.props.onClose() }} TransitionComponent={Transition}> + +
+
+ + + + + + + Settings + + + +
+
+ {!isConfigValid && ( +
+ + Error + + + The server encounter the following problem: + + + {this.state.jackConfiguration.errorState} + + + Please get the Jack Audio Server running properly on the server before attempting to configure audio. + + +
+ + )} + + +
+ + AUDIO + +
+ {JackHostStatus.getDisplayView("Status:\u00A0", this.state.jackStatus)} +
+ this.handleJackServerSettings()} + disabled={!(isConfigValid && this.state.jackServerSettings.valid)} + style={{ opacity: !(isConfigValid && this.state.jackServerSettings.valid) ? 0.6 : 1.0 }} + > + +
+ Jack Server Settings + {this.state.jackServerSettings.getSummaryText()} +
+
+ this.setState({ showJackServerSettingsDialog: false })} + onApply={(sampleRate, bufferSize, numberOfBuffers) => { + this.setState({ showJackServerSettingsDialog: false }); + this.model.setJackServerSettings(new JackServerSettings(sampleRate, bufferSize, numberOfBuffers)); + }} + /> + + + + this.handleInputSelection()} disabled={!isConfigValid} + style={{ opacity: !isConfigValid ? 0.6 : 1.0 }} + + > + +
+ Input Channels + {this.state.jackSettings.getAudioInputDisplayValue(this.state.jackConfiguration)} +
+
+ this.handleOutputSelection()} disabled={!isConfigValid} + style={{ opacity: !isConfigValid ? 0.6 : 1.0 }} + > + +
+ Output channels + {this.state.jackSettings.getAudioOutputDisplayValue(this.state.jackConfiguration)} +
+
+ +
+ MIDI + this.handleMidiSelection()} > + +
+ Select MIDI Input Channels + + {this.midiSummary()} +
+
+
+
+ +
+ SYSTEM + this.handleRestart()} > + +
+ { + this.state.restarting ? ( + Restarting... + ) : ( + Restart + ) + } +
+
+ + this.handleShutdown()} > + +
+ { + this.state.shuttingDown ? ( + Shutting down... + ) : ( + Shut down + ) + } +
+
+
+ + + +
+
+ { + (this.state.showInputSelectDialog || this.state.showOutputSelectDialog) && + ( + this.handleSelectChannelsDialogResult(selectedChannels)} + selectedChannels={selectedChannels} + availableChannels={this.state.showInputSelectDialog ? this.state.jackConfiguration.inputAudioPorts : this.state.jackConfiguration.outputAudioPorts} + /> + + ) + } + { + (this.state.showMidiSelectDialog) && + ( + this.handleSelectMidiDialogResult(selectedChannels)} + selectedChannels={this.state.jackSettings.inputMidiPorts} + availableChannels={this.state.jackConfiguration.inputMidiPorts} + /> + + ) + } + +
+ + ); + + } + + } + +); + +export default SettingsDialog; \ No newline at end of file diff --git a/react/src/SplitControlView.tsx b/react/src/SplitControlView.tsx new file mode 100644 index 0000000..ee232b9 --- /dev/null +++ b/react/src/SplitControlView.tsx @@ -0,0 +1,262 @@ +import { ReactNode } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; +import { UiPlugin } from './Lv2Plugin'; +import { + PedalBoard, PedalBoardSplitItem, ControlValue, +} from './PedalBoard'; +import PluginControl from './PluginControl'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import VuMeter from './VuMeter'; +import { SplitAbControl, SplitTypeControl, SplitMixControl, SplitPanLeftControl,SplitVolLeftControl,SplitPanRightControl,SplitVolRightControl } from './SplitUiControls'; + + +const LANDSCAPE_HEIGHT_BREAK = 500; + +const styles = (theme: Theme) => createStyles({ + frame: { + display: "block", + position: "relative", + flexDirection: "row", + flexWrap: "nowrap", + paddingTop: "8px", + paddingBottom: "0px", + height: "100%", + overflowX: "auto", + overflowY: "auto" + }, + vuMeterL: { + position: "fixed", + paddingLeft: 12, + paddingRight: 12, + left: 0, + background: "white", + zIndex: 3 + + }, + vuMeterR: { + position: "fixed", + right: 0, + marginRight: 22, + paddingLeft: 12, + background: "white", + zIndex: 3 + + }, + vuMeterRLandscape: { + position: "fixed", + right: 0, + paddingRight: 22, + paddingLeft: 12, + background: "white", + zIndex: 3 + + }, + + normalGrid: { + position: "relative", + paddingLeft: 40, + paddingRight: 40, + flex: "1 1 auto", + display: "flex", flexDirection: "row", flexWrap: "wrap", + justifyContent: "flex-start", alignItems: "flex_start" + + }, + landscapeGrid: { + paddingLeft: 40, + marginRight: 40, + display: "inline-flex", flexDirection: "row", flexWrap: "nowrap", + justifyContent: "flex-start", alignItems: "flex_start", + height: "100%" + } + +}); + +interface SplitControlViewProps extends WithStyles { + theme: Theme; + instanceId: number; + item: PedalBoardSplitItem; +}; +type SplitControlViewState = { + landscapeGrid: boolean; +}; + +const SplitControlView = + withStyles(styles, { withTheme: true })( + class extends ResizeResponsiveComponent + { + model: PiPedalModel; + + constructor(props: SplitControlViewProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + + this.state = { + landscapeGrid: false + + } + this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this); + this.onValueChanged = this.onValueChanged.bind(this); + this.onPreviewChange = this.onPreviewChange.bind(this); + } + + + onPreviewChange(key: string, value: number): void { + this.model.previewPedalBoardValue(this.props.instanceId, key, value); + } + + onValueChanged(key: string, value: number): void { + this.model.setPedalBoardControlValue(this.props.instanceId, key, value); + } + + onPedalBoardChanged(value?: PedalBoard) { + //let item = this.model.pedalBoard.get().maybeGetItem(this.props.instanceId); + //this.setState({ pedalBoardItem: item }); + } + + + componentDidMount() { + super.componentDidMount(); + this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged); + } + componentWillUnmount() { + this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged); + super.componentWillUnmount(); + } + + renderControl(plugin: UiPlugin, controlValue: ControlValue): ReactNode { + return ( +
+ + +
+ ) + } + + onWindowSizeChanged(width: number, height: number): void { + this.setState({ landscapeGrid: height < LANDSCAPE_HEIGHT_BREAK }); + } + + + render(): ReactNode { + let classes = this.props.classes; + let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId); + + if (!pedalBoardItem) + return (
); + + + let gridClass = this.state.landscapeGrid ? classes.landscapeGrid : classes.normalGrid; + let vuMeterRClass = this.state.landscapeGrid ? classes.vuMeterRLandscape : classes.vuMeterR; + let typeValue = pedalBoardItem.getControl(PedalBoardSplitItem.TYPE_KEY); + let mixValue = pedalBoardItem.getControl(PedalBoardSplitItem.MIX_KEY); + let selectValue = pedalBoardItem.getControl(PedalBoardSplitItem.SELECT_KEY); + let panLValue = pedalBoardItem.getControl(PedalBoardSplitItem.PANL_KEY); + let volumeLValue = pedalBoardItem.getControl(PedalBoardSplitItem.VOLL_KEY); + let panRValue = pedalBoardItem.getControl(PedalBoardSplitItem.PANR_KEY); + let volumeRValue = pedalBoardItem.getControl(PedalBoardSplitItem.VOLR_KEY); + + return ( +
+
+ +
+
+ +
+
+
+ { this.onValueChanged(typeValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(typeValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ { + typeValue.value === 0 && ( +
+ { this.onValueChanged(selectValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(selectValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ + ) + } + { + typeValue.value === 1 && ( +
+ { this.onValueChanged(mixValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(mixValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ + ) + } + { + typeValue.value === 2 && ( +
+ { this.onValueChanged(panLValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(panLValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ ) + } + { + typeValue.value === 2 && ( +
+ { this.onValueChanged(volumeLValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(volumeLValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ ) + } + { + typeValue.value === 2 && ( +
+ { this.onValueChanged(panRValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(panRValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ ) + } + { + typeValue.value === 2 && ( +
+ { this.onValueChanged(volumeRValue.key, value) }} + onPreviewChange={(value: number) => { this.onPreviewChange(volumeRValue.key, value) }} + requestIMEEdit={(uiControl, value) => { }} + + /> +
+ ) + } + + +
+
+ ); + + } + + } + ); + +export default SplitControlView; + diff --git a/react/src/SplitUiControls.tsx b/react/src/SplitUiControls.tsx new file mode 100644 index 0000000..f3cd4ad --- /dev/null +++ b/react/src/SplitUiControls.tsx @@ -0,0 +1,162 @@ +import {UiControl,ScalePoint} from './Lv2Plugin'; +import {PedalBoardSplitItem} from './PedalBoard'; +import Units from './Units' + + + +export const SplitTypeControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.TYPE_KEY, + name: "Type", + index: 0, + min_value: 0, + max_value: 2, + default_value: 0, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: true, + not_on_gui: false, + toggled_property: false, + scale_points: ScalePoint.deserialize_array( + [ + { value: 0, label: "A/B" }, + { value: 1, label: "Mix" }, + { value: 2, label: "L/R" } + ] + ) +}); + +export const SplitAbControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.SELECT_KEY, + name: "Select", + index: 1, + min_value: 0, + max_value: 1, + default_value: 0, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: true, + not_on_gui: false, + toggled_property: false, + scale_points: ScalePoint.deserialize_array( + [ + { value: 0, label: "A" }, + { value: 1, label: "B" }, + ] + ) +}); + + +export const SplitMixControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.MIX_KEY, + name: "Mix", + index: 2, + min_value: -1, + max_value: 1, + default_value: 0, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: false, + not_on_gui: false, + toggled_property: false, + scale_points: [] +}); + +export const SplitPanLeftControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.PANL_KEY, + name: "Pan Top", + index: 3, + min_value: -1, + max_value: 1, + default_value: 0, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: false, + not_on_gui: false, + toggled_property: false, + scale_points: [] +}); + +export const SplitVolLeftControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.VOLL_KEY, + name: "Vol Top", + index: 4, + min_value: -60, + max_value: 12, + default_value: -3, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: false, + not_on_gui: false, + toggled_property: false, + units: Units.db, + scale_points: [ + new ScalePoint().deserialize({ + value: -60, + label: "-INF" + }) + ] +}); + + +export const SplitPanRightControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.PANR_KEY, + name: "Pan Bottom", + index: 5, + min_value: -1, + max_value: 1, + default_value: 0, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: false, + not_on_gui: false, + toggled_property: false, + scale_points: [] +}); + +export const SplitVolRightControl: UiControl = new UiControl().deserialize({ + symbol: PedalBoardSplitItem.VOLR_KEY, + name: "Vol Bottom", + index: 6, + min_value: -60, + max_value: 12, + default_value: -3, + range_steps: 0, + is_logarithmic: false, + display_priority: -1, + integer_property: false, + enumeration_property: false, + not_on_gui: false, + toggled_property: false, + units: Units.db, + scale_points: [ + new ScalePoint().deserialize({ + value: -60, + label: "-INF" + }) + ] +}); + +export const SplitControls: UiControl[] = +[ + SplitTypeControl, + SplitAbControl, + SplitMixControl, + SplitPanLeftControl, + SplitVolLeftControl, + SplitPanRightControl, + SplitVolRightControl, +]; + + diff --git a/react/src/StringBuilder.tsx b/react/src/StringBuilder.tsx new file mode 100644 index 0000000..7b326dd --- /dev/null +++ b/react/src/StringBuilder.tsx @@ -0,0 +1,21 @@ + + +class StringBuilder +{ + _array: string[] = []; + + append(value: any) { + if (typeof(value) === "string") + { + this._array.push(value); + } else { + this._array.push(value+""); + } + return this; + } + toString(): string { + return this._array.join(''); + } +} + +export default StringBuilder; \ No newline at end of file diff --git a/react/src/SvgPathBuilder.tsx b/react/src/SvgPathBuilder.tsx new file mode 100644 index 0000000..53e8904 --- /dev/null +++ b/react/src/SvgPathBuilder.tsx @@ -0,0 +1,32 @@ +import StringBuilder from './StringBuilder'; + +class SvgPathBuilder { + _sb: StringBuilder = new StringBuilder(); + + moveTo(x: number, y: number): SvgPathBuilder + { + this._sb.append('M').append(x).append(',').append(y).append(' '); + return this; + } + lineTo(x: number, y: number): SvgPathBuilder + { + this._sb.append('L').append(x).append(',').append(y).append(' '); + return this; + } + bezierTo(x1: number, y1: number, x2: number, y2: number, x: number, y: number) + { + this._sb.append('C').append(x1).append(',').append(y1) + .append(' ').append(x2).append(',').append(y2) + .append(' ').append(x).append(',').append(y).append(' '); + + } + closePath(): SvgPathBuilder { + this._sb.append("Z "); + return this; + + } + + toString(): string { return this._sb.toString(); } +} + +export default SvgPathBuilder; \ No newline at end of file diff --git a/react/src/TemporaryDrawer.tsx b/react/src/TemporaryDrawer.tsx new file mode 100644 index 0000000..15260e6 --- /dev/null +++ b/react/src/TemporaryDrawer.tsx @@ -0,0 +1,93 @@ +import React, { Component } from 'react'; +import { withStyles, createStyles, WithStyles } from '@material-ui/core'; + +import Toolbar from '@material-ui/core/Toolbar'; +import IconButton from '@material-ui/core/Toolbar'; +import Drawer from '@material-ui/core/Drawer'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import { Theme } from '@material-ui/core/styles/createMuiTheme'; + + +const drawerStyles = ({ palette }: Theme) => createStyles({ + list: { + width: 250, + }, + fullList: { + width: 'auto', + }, + + drawer_header: { + color: 'white', + background: palette.primary.main, + + } +}); + +type Anchor = 'top' | 'left' | 'bottom' | 'right'; + +type CloseEventHandler = () => void; + + + +interface DrawerProps extends WithStyles { + title?: string; + position: Anchor; + is_open: boolean; + onClose?: CloseEventHandler; + children?: React.ReactChild | React.ReactChild[]; + +}; +type DrawerState = { + is_open: boolean; +} + +export const TemporaryDrawer = withStyles(drawerStyles)( + class extends Component + { + constructor(props: DrawerProps) { + super(props); + this.state = { is_open: props.is_open }; + + } + + toggleDrawer(anchor: Anchor, open: boolean): void { + this.setState({ is_open: open }); + }; + + + fireClose() { + let handler = this.props.onClose; + if (handler != null) { + handler(); + } + } + + render() { + const { classes } = this.props; + + + return ( +
+ + { this.fireClose(); }} > +
{ this.fireClose(); }} + onKeyDown={() => { this.fireClose(); }} + > + + + + + + {this.props.children} +
+
+
+
+ ); + } + } +); diff --git a/react/src/ToobCabSimView.tsx b/react/src/ToobCabSimView.tsx new file mode 100644 index 0000000..bae4b3f --- /dev/null +++ b/react/src/ToobCabSimView.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; + +import IControlViewFactory from './IControlViewFactory'; +import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel"; +import { PedalBoardItem } from './PedalBoard'; +import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView'; +import ToobFrequencyResponseView from './ToobFrequencyResponseView'; + + + +const styles = (theme: Theme) => createStyles({ +}); + +interface ToobCabSimProps extends WithStyles { + instanceId: number; + item: PedalBoardItem; + +}; +interface ToobCabSimState { + +}; + +const ToobCabSimView = + withStyles(styles, { withTheme: true })( + class extends React.Component + implements ControlViewCustomization + { + model: PiPedalModel; + + customizationId: number = 1; + + constructor(props: ToobCabSimProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + } + } + + ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[] + { + controls.splice(0,0, + ( ) + ); + return controls; + } + render() { + return (); + } + } + ); + + + +class ToobCabSimViewFactory implements IControlViewFactory { + uri: string = "http://two-play.com/plugins/toob-cab-sim"; + + Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode { + return (); + } + + +}; +export default ToobCabSimViewFactory; \ No newline at end of file diff --git a/react/src/ToobFrequencyResponseView.tsx b/react/src/ToobFrequencyResponseView.tsx new file mode 100644 index 0000000..78af6e4 --- /dev/null +++ b/react/src/ToobFrequencyResponseView.tsx @@ -0,0 +1,215 @@ +import React from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; + +import { PiPedalModelFactory, PiPedalModel, State } from "./PiPedalModel"; +import { StandardItemSize } from './PluginControlView'; +import Utility from './Utility'; +import SvgPathBuilder from './SvgPathBuilder'; + + +const FREQUENCY_RESPONSE_VECTOR_URI = "http://two-play.com/plugins/toob#frequencyResponseVector"; + +const PLOT_WIDTH = StandardItemSize.width*2-16; +const PLOT_HEIGHT = StandardItemSize.height-12; + +const styles = (theme: Theme) => createStyles({ + frame: { + width: PLOT_WIDTH, height: PLOT_HEIGHT, background: "#444", + borderRadius: 6, + marginTop: 12, marginLeft: 8, marginRight: 8, + boxShadow: "1px 4px 8px #000 inset" + }, +}); + +interface ToobFrequencyResponseProps extends WithStyles { + instanceId: number; + +}; +interface ToobFrequencyResponseState { + path: string; +}; + +const ToobFrequencyResponseView = + withStyles(styles, { withTheme: true })( + class extends React.Component + { + model: PiPedalModel; + + customizationId: number = 1; + pathRef: React.RefObject; + + constructor(props: ToobFrequencyResponseProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + path: "" + }; + + this.pathRef = React.createRef(); + this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this); + this.onStateChanged = this.onStateChanged.bind(this); + } + + onStateChanged() + { + if (this.model.state.get() === State.Ready) + { + this.requestDeferred = false; + this.requestOutstanding = false; + this.updateFrequencyResponse(); // after a reconnect. + } + } + onPedalBoardChanged() + { + this.updateFrequencyResponse(); + } + componentDidMount() + { + this.model.state.addOnChangedHandler(this.onStateChanged); + this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged); + this.updateFrequencyResponse(); + } + componentWillUnmount() + { + this.model.state.removeOnChangedHandler(this.onStateChanged); + this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged); + } + + componentDidUpdate() { + //this.updateFrequencyResponse(); + } + requestOutstanding: boolean = false; + requestDeferred: boolean = false; + + dbMinOpt: number = -35; + dbMaxOpt: number = 5; + dbTickSpacingOpt: number = 10; + + + MIN_DB_AF: number = Math.pow(10,-192/20); + fMin: number = 30; + fMax: number = 20000; + logMin: number = Math.log(this.fMin); + logMax: number = Math.log(this.fMax); + + // Size of the SVG element. + xMin: number = 0; + xMax: number = PLOT_WIDTH+4; + yMin: number = 0; + yMax: number = PLOT_HEIGHT; + dbMin: number = this.dbMaxOpt; // deliberately reversed to flip up and down. + dbMax: number = this.dbMinOpt; + dbTickSpacing: number = this.dbTickSpacingOpt; + + toX(frequency: number): number + { + var logV = Math.log(frequency); + return (this.xMax-this.xMin) * (logV-this.logMin)/(this.logMax-this.logMin) + this.xMin; + + } + toY(value: number): number { + value = Math.abs(value); + + var db; + if (value < this.MIN_DB_AF) { + db = -192.0; + } else { + db = 20*Math.log10(value); + } + var y = (db-this.dbMin)/(this.dbMax-this.dbMin)*(this.yMax-this.yMin) + this.yMin; + return y; + } + + onFrequencyResponseUpdated(data: number[]) { + let pathBuilder = new SvgPathBuilder(); + if (data.length > 2) + { + pathBuilder.moveTo(this.toX(data[0]),this.toY(data[1])) + for (let i = 2; i < data.length; i += 2) + { + pathBuilder.lineTo(this.toX(data[i]),this.toY(data[i+1])); + } + } + this.currentPath = pathBuilder.toString(); + this.setState({path: this.currentPath}); + + } + + updateFrequencyResponse() { + if (this.requestOutstanding) { // throttling. + this.requestDeferred = true; + return; + } + this.requestOutstanding = true; + this.model.getLv2Parameter(this.props.instanceId, FREQUENCY_RESPONSE_VECTOR_URI) + .then((data) => { + this.onFrequencyResponseUpdated(data); + if (this.requestDeferred) { + Utility.delay(10) // take breath + .then( + () => { + this.requestOutstanding = false; + this.requestDeferred = false; + this.updateFrequencyResponse(); + } + + ); + } else { + this.requestOutstanding = false; + } + }).catch(error => { + // assume the connection was lost. We'll get saved by a reconnect. + this.requestOutstanding = false; + this.requestDeferred = false; + }); + } + + currentPath: string = ""; + + gridLine(x0: number, y0: number, x1: number, y1: number): React.ReactNode { + return (); + } + grid(): React.ReactNode[] { + let result: React.ReactNode[] = []; + + + for (var db = Math.ceil(this.dbMax/this.dbTickSpacing)*this.dbTickSpacing; db < this.dbMin; db += this.dbTickSpacing ) + { + var y = (db-this.dbMin)/(this.dbMax-this.dbMin)*(this.yMax-this.yMin); + result.push( + this.gridLine(this.xMin,y,this.xMax,y) + ); + } + let decade0 = Math.pow(10,Math.floor(Math.log10(this.fMin))); + for (var decade = decade0; decade < this.fMax; decade *= 10) + { + for (var i = 0; i < 10; ++i) + { + var f = decade*i; + if (f > this.fMin && f < this.fMax) + { + var x = this.toX(f); + result.push(this.gridLine(x,this.yMin,x,this.yMax)); + } + } + } + return result; + } + + render() { + let classes = this.props.classes; + return ( +
+ + { this.grid() } + + + +
); + } + } + ); + + + +export default ToobFrequencyResponseView; \ No newline at end of file diff --git a/react/src/ToobInputStageView.tsx b/react/src/ToobInputStageView.tsx new file mode 100644 index 0000000..6e01875 --- /dev/null +++ b/react/src/ToobInputStageView.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; + +import IControlViewFactory from './IControlViewFactory'; +import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel"; +import { PedalBoardItem } from './PedalBoard'; +import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView'; +import ToobFrequencyResponseView from './ToobFrequencyResponseView'; + + + +const styles = (theme: Theme) => createStyles({ +}); + +interface ToobInputStageProps extends WithStyles { + instanceId: number; + item: PedalBoardItem; + +}; +interface ToobInputStageState { + +}; + +const ToobInputStageView = + withStyles(styles, { withTheme: true })( + class extends React.Component + implements ControlViewCustomization + { + model: PiPedalModel; + + customizationId: number = 1; + + constructor(props: ToobInputStageProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + } + } + + ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[] + { + let group = controls[1] as ControlGroup; + group.controls.splice(0,0, + ( ) + ); + return controls; + } + render() { + return (); + } + } + ); + + + +class ToobInputStageViewFactory implements IControlViewFactory { + uri: string = "http://two-play.com/plugins/toob-input_stage"; + + Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode { + return (); + } + + +}; +export default ToobInputStageViewFactory; \ No newline at end of file diff --git a/react/src/ToobToneStackView.tsx b/react/src/ToobToneStackView.tsx new file mode 100644 index 0000000..c81b9af --- /dev/null +++ b/react/src/ToobToneStackView.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; + +import IControlViewFactory from './IControlViewFactory'; +import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel"; +import { PedalBoardItem } from './PedalBoard'; +import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView'; +import ToobFrequencyResponseView from './ToobFrequencyResponseView'; + + + +const styles = (theme: Theme) => createStyles({ +}); + +interface ToobToneStackProps extends WithStyles { + instanceId: number; + item: PedalBoardItem; + +}; +interface ToobToneStackState { + +}; + +const ToobToneStackView = + withStyles(styles, { withTheme: true })( + class extends React.Component + implements ControlViewCustomization + { + model: PiPedalModel; + + customizationId: number = 1; + + constructor(props: ToobToneStackProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + } + } + + ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[] + { + controls.splice(0,0, + ( ) + ); + return controls; + } + render() { + return (); + } + } + ); + + + +class ToobToneStackViewFactory implements IControlViewFactory { + uri: string = "http://two-play.com/plugins/toob-tone-stack"; + + Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode { + return (); + } + + +}; +export default ToobToneStackViewFactory; \ No newline at end of file diff --git a/react/src/Units.tsx b/react/src/Units.tsx new file mode 100644 index 0000000..6bd091d --- /dev/null +++ b/react/src/Units.tsx @@ -0,0 +1,26 @@ + + + +enum Units { + none = "none", + unknown = "unknown", + bar = "bar", + beat = "beat", + bpm = "bpm", + cent = "cent", + cm = "cm", + db = "db", + hz = "hz", + khz = "khz", + km = "km", + m = "m", + mhz = "mhz", + midiNote = "midiNote", + min = "min", + ms = "ms", + pc = "pc", + s = "s", + semitone12TET = "semitone12TET" +}; + +export default Units; \ No newline at end of file diff --git a/react/src/UploadDialog.tsx b/react/src/UploadDialog.tsx new file mode 100644 index 0000000..18ebaf3 --- /dev/null +++ b/react/src/UploadDialog.tsx @@ -0,0 +1,221 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import {PiPedalModel,PiPedalModelFactory} from './PiPedalModel'; + +import Dialog from '@material-ui/core/Dialog'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import Typography from '@material-ui/core/Typography'; + + +const PRESET_EXTENSION = ".piPreset"; +const BANK_EXTENSION = ".piBank"; + +export interface UploadDialogProps { + open: boolean, + onClose: () => void, + uploadAfter: number, + onUploaded: (instanceId: number) => void + +}; + +export interface UploadDialogState { + fullScreen: boolean; +}; + +export default class UploadDialog extends ResizeResponsiveComponent { + + model: PiPedalModel; + + constructor(props: UploadDialogProps) { + super(props); + this.state = { + fullScreen: false + }; + this.model = PiPedalModelFactory.getInstance(); + + this.handlePopState = this.handlePopState.bind(this); + } + mounted: boolean = false; + + hasHooks: boolean = false; + + stateWasPopped: boolean = false; + handlePopState(e: any): any { + this.stateWasPopped = true; + let shouldClose = (!e.state || !e.state.UploadDialog); + if (shouldClose) { + this.props.onClose(); + } + } + + updateHooks(): void { + let wantHooks = this.mounted && this.props.open; + if (wantHooks !== this.hasHooks) { + this.hasHooks = wantHooks; + + if (this.hasHooks) { + this.stateWasPopped = false; + window.addEventListener("popstate", this.handlePopState); + // eslint-disable-next-line no-restricted-globals + let state = history.state; + if (!state) { + state = {}; + } + state.UploadDialog = true; + + // eslint-disable-next-line no-restricted-globals + history.pushState( + state, + "Upload", + "#UploadDialog" + ); + } else { + window.removeEventListener("popstate", this.handlePopState); + if (!this.stateWasPopped) { + // eslint-disable-next-line no-restricted-globals + history.back(); + } + } + + } + } + onWindowSizeChanged(width: number, height: number): void { + this.setState({ fullScreen: height < 200 }) + } + + + componentDidMount() { + super.componentDidMount(); + this.mounted = true; + this.updateHooks(); + } + componentWillUnmount() { + super.componentDidMount(); + this.mounted = false; + this.updateHooks(); + } + + componentDidUpdate() { + this.updateHooks(); + } + + handleClose(): void { + this.props.onClose(); + } + + handleOk(): void { + this.props.onClose(); + } + + async uploadFiles(fileList: FileList) + { + try { + let uploadAfter = this.props.uploadAfter; + for (let i = 0; i < fileList.length; ++i) + { + uploadAfter = await this.model.uploadPreset(fileList[i],uploadAfter); + } + this.props.onUploaded(uploadAfter); + } catch(error) { + this.model.showAlert(error); + }; + this.props.onClose(); + } + handleDrop(e: React.DragEvent) { + e.preventDefault(); + e.currentTarget.style.background = ""; + + if (this.wantsTransfer(e.dataTransfer)) { + this.uploadFiles(e.dataTransfer.files) + .then(() => { + this.handleClose(); + }) + .catch((error)=> { + this.handleClose(); + this.model.showAlert(error); + }); + } + } + + getFileExtension(name: string): string { + let pos = name.lastIndexOf('.'); + if (pos !== -1) { + return name.substring(pos); + } + return ""; + } + + wantsTransfer(fileList: DataTransfer): boolean { + if (fileList.files.length === 0) return false; + + for (let i = 0; i < fileList.files.length; ++i) { + let file = fileList.files[i]; + let extension = this.getFileExtension(file.name); + if (extension !== PRESET_EXTENSION && extension !== BANK_EXTENSION) return false; + } + return true; + } + handleDragOver(e: React.DragEvent) { + e.currentTarget.style.background = "#D8D8D8"; + e.preventDefault(); + } + + handleButtonSelect(e: React.ChangeEvent) + { + if (e.currentTarget.files) + { + this.uploadFiles(e.currentTarget.files); + } + } + + render() { + + + return ( + this.handleClose()} style={{}} + fullScreen={this.state.fullScreen} + > + Upload preset + +
{ this.handleDragOver(e); }} + onDragLeave={(e) => { e.currentTarget.style.background = ""; e.preventDefault(); }} + onDragOver={(e) => { this.handleDragOver(e); }} + onDrop={(e) => { + this.handleDrop(e); + }} + > + Drop files here +
+
+ + + + + +
+ ); + } +} \ No newline at end of file diff --git a/react/src/Utility.tsx b/react/src/Utility.tsx new file mode 100644 index 0000000..01a92b8 --- /dev/null +++ b/react/src/Utility.tsx @@ -0,0 +1,140 @@ +import { PiPedalArgumentError } from './PiPedalError'; + +export function nullCast(value: T | null | undefined): T { + if (!value) throw new PiPedalArgumentError("Unexpected null value."); + return value; +} + + +const FLAT = "\u266D"; + + +const LONG_PRESS_TIME_MS = 500; // current android long-press. + +export function getLongPressTimeMs(): number { return LONG_PRESS_TIME_MS; } + +export interface ControlEntry { + value: number; + displayName: string; +}; + +const Utility = class { + static isTouchDevice(): boolean { + return navigator.maxTouchPoints > 0; + } + + static hasIMEKeyboard(): boolean { + if (/Mobi|Android/i.test(navigator.userAgent)) { + return true; + } + return false; + } + + static delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + + static NOTE_DEGREES: string[] = + [ + "C", "C#", "D", "E" + FLAT, "E", "F", "F#", "G", "A" + FLAT, "A", "B" + FLAT, "B" + ]; + static midiNoteName(noteNumber: number): string { + let n = noteNumber - 24; + let octave = Math.floor(n / 12); + let iNote = n % 12; + if (iNote < 0) iNote += 12; + + return Utility.NOTE_DEGREES[iNote] + octave; + + + } + + static validMidiControllers: ControlEntry[] = [ + { value: 1, displayName: "CC-1 Mod Wheel" }, + { value: 2, displayName: "CC-2 Breath controller" }, + { value: 3, displayName: "CC-3" }, + { value: 4, displayName: "CC-4 Foot Pedal" }, + { value: 5, displayName: "CC-5 Portamento Time" }, + { value: 7, displayName: "CC-7 Volume" }, + { value: 8, displayName: "CC-8 Balance" }, + { value: 10, displayName: "CC-10 Pan position" }, + { value: 11, displayName: "CC-11 Expression" }, + { value: 12, displayName: "CC-12 Effect Control 1" }, + { value: 13, displayName: "CC-13 Effect Control 2" }, + { value: 14, displayName: "CC-14" }, + { value: 15, displayName: "CC-15" }, + { value: 16, displayName: "CC-16" }, + { value: 17, displayName: "CC-17" }, + { value: 18, displayName: "CC-18" }, + { value: 19, displayName: "CC-19" }, + { value: 20, displayName: "CC-20" }, + { value: 21, displayName: "CC-21" }, + { value: 22, displayName: "CC-22" }, + { value: 23, displayName: "CC-23" }, + { value: 24, displayName: "CC-24" }, + { value: 25, displayName: "CC-25" }, + { value: 26, displayName: "CC-26" }, + { value: 27, displayName: "CC-27" }, + { value: 28, displayName: "CC-28" }, + { value: 29, displayName: "CC-29" }, + { value: 30, displayName: "CC-30" }, + { value: 31, displayName: "CC-31" }, + // Control LSB. + { value: 64, displayName: "CC-64 Hold Pedal" }, + { value: 65, displayName: "CC-65 Portamento" }, + { value: 66, displayName: "CC-66 Sustenuto Pedal" }, + { value: 67, displayName: "CC-67 Soft Pedal" }, + { value: 68, displayName: "CC-68 Legato Pedal" }, + { value: 69, displayName: "CC-69 Hold 2 Pedal" }, + { value: 70, displayName: "CC-70 Sound Variation" }, + { value: 71, displayName: "CC-71 Resonance" }, + { value: 72, displayName: "CC-72 Sound Release Time" }, + { value: 73, displayName: "CC-73 Sound Attack Time" }, + { value: 74, displayName: "CC-74 Frequency Cutoff" }, + { value: 75, displayName: "CC-75" }, + { value: 76, displayName: "CC-76" }, + { value: 77, displayName: "CC-77" }, + { value: 78, displayName: "CC-78" }, + { value: 79, displayName: "CC-79" }, + { value: 80, displayName: "CC-80 Decay" }, + { value: 81, displayName: "CC-81" }, + { value: 82, displayName: "CC-82" }, + { value: 83, displayName: "CC-83" }, + { value: 91, displayName: "CC-91 Reverb Level" }, + { value: 92, displayName: "CC-92 Tremolo Level" }, + { value: 93, displayName: "CC-93 Chorus Level" }, + { value: 94, displayName: "CC-94 Detune" }, + { value: 95, displayName: "CC-95 Phaser Level" }, + // RPN/DATA controls + { value: 102, displayName: "CC-102" }, + { value: 103, displayName: "CC-103" }, + { value: 104, displayName: "CC-104" }, + { value: 105, displayName: "CC-105" }, + { value: 106, displayName: "CC-106" }, + { value: 107, displayName: "CC-107" }, + { value: 108, displayName: "CC-108" }, + { value: 109, displayName: "CC-109" }, + { value: 110, displayName: "CC-110" }, + { value: 111, displayName: "CC-111" }, + { value: 112, displayName: "CC-112" }, + { value: 113, displayName: "CC-113" }, + { value: 114, displayName: "CC-114" }, + { value: 115, displayName: "CC-115" }, + { value: 116, displayName: "CC-116" }, + { value: 117, displayName: "CC-117" }, + { value: 118, displayName: "CC-118" }, + { value: 119, displayName: "CC-119" }, + { value: 120, displayName: "CC-120 All Sound Off" }, + { value: 121, displayName: "CC-121 All Controllers Off" }, + { value: 122, displayName: "CC-122 Local Keyboard" }, + { value: 123, displayName: "CC-123 All Notes Off" }, + { value: 124, displayName: "CC-124 Omni Mode Off" }, + { value: 125, displayName: "CC-125 Omni Mode On" }, + { value: 126, displayName: "CC-126 Mono " }, + { value: 127, displayName: "CC-127 Poly" }, + ]; + +}; + +export default Utility; diff --git a/react/src/VuMeter.tsx b/react/src/VuMeter.tsx new file mode 100644 index 0000000..c8d92dd --- /dev/null +++ b/react/src/VuMeter.tsx @@ -0,0 +1,399 @@ +import React, { Component } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiPedalModel, PiPedalModelFactory, VuUpdateInfo, VuSubscriptionHandle } from './PiPedalModel'; + + +const DISPLAY_HEIGHT = 110; +const BORDER_THICKNESS = 2; +const TELLTALE_HEIGHT = 4; +const CHANNEL_WIDTH = 4; +const TELLTALE_HOLD_MS = 2000; +const TELLTALE_DECAY_RATE = -20 / 1000.0; // -20db in one second. + + +const INTERIOR_DISPLAY_HEIGHT = DISPLAY_HEIGHT - BORDER_THICKNESS * 2; + + +const MIN_DB = -35; +const MAX_DB = 6; +const DB_YELLOW = -12; + + + +interface VuChannelData { + value: number; + redDiv: HTMLDivElement; + yellowDiv: HTMLDivElement; + greenDiv: HTMLDivElement; + telltaleDiv: HTMLDivElement; + +}; + +class TelltaleState { + telltaleDb: number = MIN_DB; + lastTelltaleTime: number = 0; + telltaleHoldTime: number = 0; + + reset() : void { + this.telltaleHoldTime = 0; + this.lastTelltaleTime = 0; + this.telltaleDb = MIN_DB; + } + getValue(currentDb: number): number { + let t = new Date().getTime(); + + let holdValue: number; + if (t < this.telltaleHoldTime) { + holdValue = this.telltaleDb; + } else { + if (this.telltaleHoldTime === 0) { + holdValue = MIN_DB; + } else { + holdValue = this.telltaleDb + (t - this.telltaleHoldTime) * TELLTALE_DECAY_RATE; + if (holdValue < MIN_DB) { + this.telltaleDb = holdValue = MIN_DB; + this.telltaleHoldTime = t + 100 * 1000; // wait for a long time. + } + } + } + + if (currentDb > holdValue) { + this.telltaleDb = currentDb; + this.telltaleHoldTime = t + TELLTALE_HOLD_MS; + return currentDb; + } else { + return holdValue; + } + } + +}; + +const LEFT_X = BORDER_THICKNESS; +const RIGHT_X = BORDER_THICKNESS + + CHANNEL_WIDTH + BORDER_THICKNESS; + +const styles = ({ palette }: Theme) => createStyles({ + frame: { + position: "relative", + width: CHANNEL_WIDTH + 2*BORDER_THICKNESS, + borderTop: BORDER_THICKNESS + "px black solid", + borderBottom: BORDER_THICKNESS + "px black solid", + height: DISPLAY_HEIGHT, + background: "black", + overflow: "hidden", + marginLeft: (CHANNEL_WIDTH+BORDER_THICKNESS)/2, + marginRight: (CHANNEL_WIDTH+BORDER_THICKNESS)/2 + }, + frameStereo: { + position: "relative", + width: 2*CHANNEL_WIDTH + 3*BORDER_THICKNESS, + borderTop: BORDER_THICKNESS + "px black solid", + borderBottom: BORDER_THICKNESS + "px black solid", + height: DISPLAY_HEIGHT, + background: "black", + overflow: "hidden", + }, + redFrameL: { + position: "absolute", + top: "100%", + left: LEFT_X, + width: CHANNEL_WIDTH, + height: DISPLAY_HEIGHT - 2, + background: "#F00" + }, + yellowFrameL: { + top: "100%", + left: LEFT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#CC0" + }, + greenFrameL: { + top: "100%", + left: LEFT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#0C2" + }, + indicatorL: { + position: "absolute", + left: LEFT_X, + width: CHANNEL_WIDTH, + height: TELLTALE_HEIGHT + "px", + top: "100%", + background: "#F00" + + }, + redFrameR: { + position: "absolute", + top: "100%", + left: RIGHT_X, + width: CHANNEL_WIDTH, + height: DISPLAY_HEIGHT - 2, + background: "#F00" + }, + yellowFrameR: { + top: "100%", + left: RIGHT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#CC0" + }, + greenFrameR: { + top: "100%", + left: RIGHT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#0C2" + }, + indicatorR: { + position: "absolute", + left: RIGHT_X, + width: CHANNEL_WIDTH, + height: TELLTALE_HEIGHT + "px", + top: "100%", + background: "#F00" + + } + +}); + + + +interface VuMeterProps extends WithStyles { + instanceId: number; + display: "input" | "output"; + theme: Theme; +}; + +interface VuMeterState { + isStereo: boolean; +}; + +function aToDb(value: number): number { + if (value === 0) return -96; + return Math.log10(Math.abs(value)) * 20; +} + +function dbToY(db: number): number { + if (db < MIN_DB) db = MIN_DB; + if (db > MAX_DB) db = MAX_DB; + + let y = INTERIOR_DISPLAY_HEIGHT - (db - MIN_DB) / (MAX_DB - MIN_DB) * INTERIOR_DISPLAY_HEIGHT;; + return y; +} + +export const VuMeter = + withStyles(styles, { withTheme: true })( + class extends Component + { + divRef: React.RefObject = React.createRef(); + model: PiPedalModel; + + yZero: number; + yYellow: number; + + constructor(props: VuMeterProps) { + super(props); + this.state = { + isStereo: false + }; + this.model = PiPedalModelFactory.getInstance(); + + this.yZero = dbToY(0); + this.yYellow = dbToY(DB_YELLOW); + + this.onVuChanged = this.onVuChanged.bind(this); + + } + + + telltaleStateL: TelltaleState = new TelltaleState(); + telltaleStateR: TelltaleState = new TelltaleState(); + + vuInfo?: VuUpdateInfo; + requesttedStereoState: boolean = false; + + onVuChanged(vuInfo: VuUpdateInfo): void { + let value: number; + let valueR: number; + + this.vuInfo = vuInfo; + + + let isStereo: boolean; + + if (this.props.display === "input") { + value = vuInfo.inputMaxValueL; + valueR = vuInfo.inputMaxValueR; + isStereo = vuInfo.isStereoInput; + } else { + isStereo = vuInfo.isStereoOutput; + value = vuInfo.outputMaxValueL; + valueR = vuInfo.outputMaxValueR; + } + if (this.state.isStereo !== isStereo) + { + if (isStereo !== this.requesttedStereoState) // guard against overrunning the layout engine. + { + this.requesttedStereoState = isStereo; + + this.setState({ + isStereo: isStereo + }); + return; // we can't procede without stereo layout. + } + } + + let childNodes = this.divRef.current!.childNodes; + + let vuData: VuChannelData = { + value: value, + redDiv: childNodes[0] as HTMLDivElement, + yellowDiv: childNodes[1] as HTMLDivElement, + greenDiv: childNodes[2] as HTMLDivElement, + telltaleDiv: childNodes[3] as HTMLDivElement + }; + this.updateChannel(vuData,this.telltaleStateL); + if (this.state.isStereo) { + vuData = { + value: valueR, + redDiv: childNodes[4] as HTMLDivElement, + yellowDiv: childNodes[5] as HTMLDivElement, + greenDiv: childNodes[6] as HTMLDivElement, + telltaleDiv: childNodes[7] as HTMLDivElement + }; + this.updateChannel(vuData, this.telltaleStateR); + } + } + + resetTelltales() { + this.telltaleStateL.reset(); + this.telltaleStateR.reset(); + } + updateChannel(vuData: VuChannelData, telltaleState: TelltaleState) { + let db = aToDb(vuData.value); + if (db > MAX_DB) db = MAX_DB; + if (db < MIN_DB) db = MIN_DB; + + let y = dbToY(db); + let INVISIBLE_Y = INTERIOR_DISPLAY_HEIGHT + "px"; + if (y >= this.yYellow) { + // green only. + vuData.greenDiv.style.top = y + "px"; + vuData.yellowDiv.style.top = INVISIBLE_Y; + vuData.redDiv.style.top = INVISIBLE_Y; + } else { + vuData.greenDiv.style.top = this.yYellow + "px"; + if (y >= this.yZero) { + vuData.yellowDiv.style.top = y + "px"; + vuData.redDiv.style.top = INVISIBLE_Y; + } else { + vuData.yellowDiv.style.top = this.yZero + "px"; + vuData.redDiv.style.top = y + "px"; + } + } + let dbTelltale = telltaleState.getValue(db); + let yTelltale = dbToY(dbTelltale); + + if (yTelltale < this.yZero) { + vuData.telltaleDiv.style.background = "#F00"; + } else if (yTelltale < this.yYellow) { + vuData.telltaleDiv.style.background = "#CC0"; + } else { + vuData.telltaleDiv.style.background = "#0F2"; + } + if (yTelltale > INTERIOR_DISPLAY_HEIGHT - TELLTALE_HEIGHT) { + // non-zero and zero are different displays. + // zero: nothing.. tiny: show the telltale. + if (vuData.value !== 0) { + yTelltale = INTERIOR_DISPLAY_HEIGHT - TELLTALE_HEIGHT; + } else { + yTelltale = INTERIOR_DISPLAY_HEIGHT; + } + } + vuData.telltaleDiv.style.top = yTelltale + "px"; + + + } + subscriptionHandle?: VuSubscriptionHandle; + + subscribedInstanceId?: number; + + addVuSubscription() { + this.removeVuSubscription(); + if (this.props.instanceId !== -1) { + this.subscribedInstanceId = this.props.instanceId; + this.subscriptionHandle = this.model.addVuSubscription(this.props.instanceId, this.onVuChanged); + this.resetTelltales(); + } + } + removeVuSubscription() { + if (this.subscriptionHandle) { + this.model.removeVuSubscription(this.subscriptionHandle); + this.subscriptionHandle = undefined; + this.subscribedInstanceId = undefined; + } + } + + componentDidUpdate() + { + if (this.subscribedInstanceId) + { + if (this.props.instanceId !== this.subscribedInstanceId) + { + this.removeVuSubscription(); + this.addVuSubscription(); + } + } + + } + + + render() { + let classes = this.props.classes; + + if (!this.state.isStereo) { + return (
+
+
+
+
+
); + } else { + return (
+
+
+
+
+ +
+
+
+
+ +
); + + } + } + + + componentDidMount() { + + this.addVuSubscription(); + } + componentWillUnmount() { + this.removeVuSubscription(); + } + } + ); + +export default VuMeter; + + + diff --git a/react/src/Vumeter.tsx.bak b/react/src/Vumeter.tsx.bak new file mode 100644 index 0000000..e73b9df --- /dev/null +++ b/react/src/Vumeter.tsx.bak @@ -0,0 +1,399 @@ +import React, { Component } from 'react'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import { PiddleModel, PiddleModelFactory, VuUpdateInfo, VuSubscriptionHandle } from './PiddleModel'; + + +const DISPLAY_HEIGHT = 110; +const BORDER_THICKNESS = 2; +const TELLTALE_HEIGHT = 4; +const CHANNEL_WIDTH = 4; +const TELLTALE_HOLD_MS = 2000; +const TELLTALE_DECAY_RATE = -20 / 1000.0; // -20db in one second. + + +const INTERIOR_DISPLAY_HEIGHT = DISPLAY_HEIGHT - BORDER_THICKNESS * 2; + + +const MIN_DB = -35; +const MAX_DB = 6; +const DB_YELLOW = -12; + + + +interface VuChannelData { + value: number; + redDiv: HTMLDivElement; + yellowDiv: HTMLDivElement; + greenDiv: HTMLDivElement; + telltaleDiv: HTMLDivElement; + +}; + +class TelltaleState { + telltaleDb: number = MIN_DB; + lastTelltaleTime: number = 0; + telltaleHoldTime: number = 0; + + reset() : void { + this.telltaleHoldTime = 0; + this.lastTelltaleTime = 0; + this.telltaleDb = MIN_DB; + } + getValue(currentDb: number): number { + let t = new Date().getTime(); + + let holdValue: number; + if (t < this.telltaleHoldTime) { + holdValue = this.telltaleDb; + } else { + if (this.telltaleHoldTime === 0) { + holdValue = MIN_DB; + } else { + holdValue = this.telltaleDb + (t - this.telltaleHoldTime) * TELLTALE_DECAY_RATE; + if (holdValue < MIN_DB) { + this.telltaleDb = holdValue = MIN_DB; + this.telltaleHoldTime = t + 100 * 1000; // wait for a long time. + } + } + } + + if (currentDb > holdValue) { + this.telltaleDb = currentDb; + this.telltaleHoldTime = t + TELLTALE_HOLD_MS; + return currentDb; + } else { + return holdValue; + } + } + +}; + +const LEFT_X = BORDER_THICKNESS; +const RIGHT_X = BORDER_THICKNESS + + CHANNEL_WIDTH + BORDER_THICKNESS; + +const styles = ({ palette }: Theme) => createStyles({ + frame: { + position: "relative", + width: CHANNEL_WIDTH + 2*BORDER_THICKNESS, + borderTop: BORDER_THICKNESS + "px black solid", + borderBottom: BORDER_THICKNESS + "px black solid", + height: DISPLAY_HEIGHT, + background: "black", + overflow: "hidden", + marginLeft: (CHANNEL_WIDTH+BORDER_THICKNESS)/2, + marginRight: (CHANNEL_WIDTH+BORDER_THICKNESS)/2 + }, + frameStereo: { + position: "relative", + width: 2*CHANNEL_WIDTH + 3*BORDER_THICKNESS, + borderTop: BORDER_THICKNESS + "px black solid", + borderBottom: BORDER_THICKNESS + "px black solid", + height: DISPLAY_HEIGHT, + background: "black", + overflow: "hidden", + }, + redFrameL: { + position: "absolute", + top: "100%", + left: LEFT_X, + width: CHANNEL_WIDTH, + height: DISPLAY_HEIGHT - 2, + background: "#F00" + }, + yellowFrameL: { + top: "100%", + left: LEFT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#CC0" + }, + greenFrameL: { + top: "100%", + left: LEFT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#0C2" + }, + indicatorL: { + position: "absolute", + left: LEFT_X, + width: CHANNEL_WIDTH, + height: TELLTALE_HEIGHT + "px", + top: "100%", + background: "#F00" + + }, + redFrameR: { + position: "absolute", + top: "100%", + left: RIGHT_X, + width: CHANNEL_WIDTH, + height: DISPLAY_HEIGHT - 2, + background: "#F00" + }, + yellowFrameR: { + top: "100%", + left: RIGHT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#CC0" + }, + greenFrameR: { + top: "100%", + left: RIGHT_X, + width: CHANNEL_WIDTH, + position: "absolute", + height: DISPLAY_HEIGHT - 2, + background: "#0C2" + }, + indicatorR: { + position: "absolute", + left: RIGHT_X, + width: CHANNEL_WIDTH, + height: TELLTALE_HEIGHT + "px", + top: "100%", + background: "#F00" + + } + +}); + + + +interface VuMeterProps extends WithStyles { + instanceId: number; + display: "input" | "output"; + theme: Theme; +}; + +interface VuMeterState { + isStereo: boolean; +}; + +function aToDb(value: number): number { + if (value === 0) return -96; + return Math.log10(Math.abs(value)) * 20; +} + +function dbToY(db: number): number { + if (db < MIN_DB) db = MIN_DB; + if (db > MAX_DB) db = MAX_DB; + + let y = INTERIOR_DISPLAY_HEIGHT - (db - MIN_DB) / (MAX_DB - MIN_DB) * INTERIOR_DISPLAY_HEIGHT;; + return y; +} + +export const VuMeter = + withStyles(styles, { withTheme: true })( + class extends Component + { + divRef: React.RefObject = React.createRef(); + model: PiddleModel; + + yZero: number; + yYellow: number; + + constructor(props: VuMeterProps) { + super(props); + this.state = { + isStereo: false + }; + this.model = PiddleModelFactory.getInstance(); + + this.yZero = dbToY(0); + this.yYellow = dbToY(DB_YELLOW); + + this.onVuChanged = this.onVuChanged.bind(this); + + } + + + telltaleStateL: TelltaleState = new TelltaleState(); + telltaleStateR: TelltaleState = new TelltaleState(); + + vuInfo?: VuUpdateInfo; + requesttedStereoState: boolean = false; + + onVuChanged(vuInfo: VuUpdateInfo): void { + let value: number; + let valueR: number; + + this.vuInfo = vuInfo; + + + let isStereo: boolean; + + if (this.props.display === "input") { + value = vuInfo.inputMaxValueL; + valueR = vuInfo.inputMaxValueR; + isStereo = vuInfo.isStereoInput; + } else { + isStereo = vuInfo.isStereoOutput; + value = vuInfo.outputMaxValueL; + valueR = vuInfo.outputMaxValueR; + } + if (this.state.isStereo !== isStereo) + { + if (isStereo !== this.requesttedStereoState) // guard against overrunning the layout engine. + { + this.requesttedStereoState = isStereo; + + this.setState({ + isStereo: isStereo + }); + return; // we can't procede without stereo layout. + } + } + + let childNodes = this.divRef.current!.childNodes; + + let vuData: VuChannelData = { + value: value, + redDiv: childNodes[0] as HTMLDivElement, + yellowDiv: childNodes[1] as HTMLDivElement, + greenDiv: childNodes[2] as HTMLDivElement, + telltaleDiv: childNodes[3] as HTMLDivElement + }; + this.updateChannel(vuData,this.telltaleStateL); + if (this.state.isStereo) { + vuData = { + value: valueR, + redDiv: childNodes[4] as HTMLDivElement, + yellowDiv: childNodes[5] as HTMLDivElement, + greenDiv: childNodes[6] as HTMLDivElement, + telltaleDiv: childNodes[7] as HTMLDivElement + }; + this.updateChannel(vuData, this.telltaleStateR); + } + } + + resetTelltales() { + this.telltaleStateL.reset(); + this.telltaleStateR.reset(); + } + updateChannel(vuData: VuChannelData, telltaleState: TelltaleState) { + let db = aToDb(vuData.value); + if (db > MAX_DB) db = MAX_DB; + if (db < MIN_DB) db = MIN_DB; + + let y = dbToY(db); + let INVISIBLE_Y = INTERIOR_DISPLAY_HEIGHT + "px"; + if (y >= this.yYellow) { + // green only. + vuData.greenDiv.style.top = y + "px"; + vuData.yellowDiv.style.top = INVISIBLE_Y; + vuData.redDiv.style.top = INVISIBLE_Y; + } else { + vuData.greenDiv.style.top = this.yYellow + "px"; + if (y >= this.yZero) { + vuData.yellowDiv.style.top = y + "px"; + vuData.redDiv.style.top = INVISIBLE_Y; + } else { + vuData.yellowDiv.style.top = this.yZero + "px"; + vuData.redDiv.style.top = y + "px"; + } + } + let dbTelltale = telltaleState.getValue(db); + let yTelltale = dbToY(dbTelltale); + + if (yTelltale < this.yZero) { + vuData.telltaleDiv.style.background = "#F00"; + } else if (yTelltale < this.yYellow) { + vuData.telltaleDiv.style.background = "#CC0"; + } else { + vuData.telltaleDiv.style.background = "#0F2"; + } + if (yTelltale > INTERIOR_DISPLAY_HEIGHT - TELLTALE_HEIGHT) { + // non-zero and zero are different displays. + // zero: nothing.. tiny: show the telltale. + if (vuData.value !== 0) { + yTelltale = INTERIOR_DISPLAY_HEIGHT - TELLTALE_HEIGHT; + } else { + yTelltale = INTERIOR_DISPLAY_HEIGHT; + } + } + vuData.telltaleDiv.style.top = yTelltale + "px"; + + + } + subscriptionHandle?: VuSubscriptionHandle; + + subscribedInstanceId?: number; + + addVuSubscription() { + this.removeVuSubscription(); + if (this.props.instanceId !== -1) { + this.subscribedInstanceId = this.props.instanceId; + this.subscriptionHandle = this.model.addVuSubscription(this.props.instanceId, this.onVuChanged); + this.resetTelltales(); + } + } + removeVuSubscription() { + if (this.subscriptionHandle) { + this.model.removeVuSubscription(this.subscriptionHandle); + this.subscriptionHandle = undefined; + this.subscribedInstanceId = undefined; + } + } + + componentDidUpdate() + { + if (this.subscribedInstanceId) + { + if (this.props.instanceId !== this.subscribedInstanceId) + { + this.removeVuSubscription(); + this.addVuSubscription(); + } + } + + } + + + render() { + let classes = this.props.classes; + + if (!this.state.isStereo) { + return (
+
+
+
+
+
); + } else { + return (
+
+
+
+
+ +
+
+
+
+ +
); + + } + } + + + componentDidMount() { + + this.addVuSubscription(); + } + componentWillUnmount() { + this.removeVuSubscription(); + } + } + ); + +export default VuMeter; + + + diff --git a/react/src/index.css b/react/src/index.css new file mode 100644 index 0000000..ec2585e --- /dev/null +++ b/react/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/react/src/index.tsx b/react/src/index.tsx new file mode 100644 index 0000000..ef2edf8 --- /dev/null +++ b/react/src/index.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import reportWebVitals from './reportWebVitals'; + +ReactDOM.render( + + + , + document.getElementById('root') +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/react/src/logo.svg b/react/src/logo.svg new file mode 100644 index 0000000..9dfc1c0 --- /dev/null +++ b/react/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/src/react-app-env.d.ts b/react/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/react/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/react/src/reportWebVitals.ts b/react/src/reportWebVitals.ts new file mode 100644 index 0000000..49a2a16 --- /dev/null +++ b/react/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/react/src/setupTests.ts b/react/src/setupTests.ts new file mode 100644 index 0000000..8f2609b --- /dev/null +++ b/react/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/react/start b/react/start new file mode 100755 index 0000000..0186425 --- /dev/null +++ b/react/start @@ -0,0 +1 @@ +npm start diff --git a/react/tsconfig.json b/react/tsconfig.json new file mode 100644 index 0000000..a191348 --- /dev/null +++ b/react/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext", + "es2020" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/src/Banks.cpp b/src/Banks.cpp new file mode 100644 index 0000000..cd24b4b --- /dev/null +++ b/src/Banks.cpp @@ -0,0 +1,43 @@ +#include "pch.h" +#include "Banks.hpp" + +using namespace pipedal; + +JSON_MAP_BEGIN(PresetIndexEntry) + JSON_MAP_REFERENCE(PresetIndexEntry,instanceId) + JSON_MAP_REFERENCE(PresetIndexEntry,name) +JSON_MAP_END() + + + +JSON_MAP_BEGIN(PresetIndex) + JSON_MAP_REFERENCE(PresetIndex,selectedInstanceId) + JSON_MAP_REFERENCE(PresetIndex,presetChanged) + JSON_MAP_REFERENCE(PresetIndex,presets) +JSON_MAP_END() + + +JSON_MAP_BEGIN(BankIndex) + JSON_MAP_REFERENCE(BankIndex,selectedBank) + JSON_MAP_REFERENCE(BankIndex,nextInstanceId) + JSON_MAP_REFERENCE(BankIndex,entries) +JSON_MAP_END() + +JSON_MAP_BEGIN(BankIndexEntry) + JSON_MAP_REFERENCE(BankIndexEntry,instanceId) + JSON_MAP_REFERENCE(BankIndexEntry,name) +JSON_MAP_END() + +JSON_MAP_BEGIN(BankFile) + JSON_MAP_REFERENCE(BankFile,name) + JSON_MAP_REFERENCE(BankFile,nextInstanceId) + JSON_MAP_REFERENCE(BankFile,selectedPreset) + JSON_MAP_REFERENCE(BankFile,presets) +JSON_MAP_END() + +JSON_MAP_BEGIN(BankFileEntry) + JSON_MAP_REFERENCE(BankFileEntry,instanceId) + JSON_MAP_REFERENCE(BankFileEntry,preset) +JSON_MAP_END() + + diff --git a/src/Banks.hpp b/src/Banks.hpp new file mode 100644 index 0000000..160ef73 --- /dev/null +++ b/src/Banks.hpp @@ -0,0 +1,300 @@ +#pragma once + +#include "json.hpp" +#include "PedalBoard.hpp" +#include "PiPedalException.hpp" + +namespace pipedal { + +#define GETTER_SETTER_REF(name) \ + decltype(name##_)& name() { return name##_;} \ + const decltype(name##_)& name() const { return name##_;} \ + void name(const decltype(name##_) &value) { name##_ = value; } + +#define GETTER_SETTER_VEC(name) \ + decltype(name##_)& name() { return name##_;} \ + const decltype(name##_)& name() const { return name##_;} + + +#define GETTER_SETTER(name) \ + decltype(name##_) name() const { return name##_;} \ + void name(decltype(name##_) value) { name##_ = value; } + + +class PresetIndexEntry { + int64_t instanceId_ = 0; + std::string name_; +public: + GETTER_SETTER(instanceId); + GETTER_SETTER(name); + DECLARE_JSON_MAP(PresetIndexEntry); +}; + +class PresetIndex { + int64_t selectedInstanceId_ = -1; + bool presetChanged_ = false; + std::vector presets_; +public: + bool GetPresetName(int64_t instanceId, std::string*pResult) { + for (size_t i = 0; i < presets_.size(); ++i) + { + if (presets_[i].instanceId() == instanceId) + { + *pResult = presets_[i].name(); + return true; + } + } + return false; + } + GETTER_SETTER(selectedInstanceId); + GETTER_SETTER_VEC(presets); + GETTER_SETTER(presetChanged); + + DECLARE_JSON_MAP(PresetIndex); +}; + + +class BankFileEntry { + int64_t instanceId_; + PedalBoard preset_; +public: + GETTER_SETTER(instanceId); + GETTER_SETTER_REF(preset); + + DECLARE_JSON_MAP(BankFileEntry); +}; +class BankFile { + std::string name_; + int64_t nextInstanceId_ = 0; + int64_t selectedPreset_ = -1; + std::vector> presets_; + +public: + GETTER_SETTER(name); + GETTER_SETTER(nextInstanceId); + GETTER_SETTER(selectedPreset); + GETTER_SETTER_VEC(presets); + + void clear() + { + nextInstanceId_ = 0; + presets_.clear(); + selectedPreset_ = -1; + } + void move(size_t from, size_t to) + { + if (from >= this->presets_.size()) { + throw std::invalid_argument("Argument out of range."); + } + if (to >= this->presets_.size()) { + throw std::invalid_argument("Argument out of range."); + } + std::unique_ptr t = std::move(this->presets_[from]); + presets_.erase(presets_.begin()+from); + presets_.insert(presets_.begin()+to,std::move(t)); + } + int64_t addPreset(const PedalBoard&preset, int64_t afterItem = -1) + { + if (hasName(preset.name())) + { + throw PiPedalStateException("A preset by that name already exists."); + } + std::unique_ptr entry = std::make_unique(); + entry->instanceId(++nextInstanceId_); + entry->preset(preset); + int64_t instanceId = entry->instanceId(); + if (afterItem == -1) + { + this->presets_.push_back(std::move(entry)); + } else { + for (auto it = this->presets_.begin(); it != this->presets_.end(); ++it) + { + if ((*it)->instanceId() == afterItem) + { + ++it; + this->presets_.insert(it,std::move(entry)); + break; + } + } + } + return instanceId; + } + bool hasItem(int64_t instanceId) + { + for (size_t i = 0; i < presets_.size(); ++i) + { + if (presets_[i]->instanceId() == instanceId) + { + return true; + } + } + return false; + } + bool hasName(const std::string &name) { + for (size_t i = 0; i < presets_.size(); ++i) + { + if (presets_[i]->preset().name() == name) + { + return true; + } + } + return false; + } + bool renamePreset(int64_t instanceId, const std::string&name) + { + if (hasName(name)) + { + throw PiPedalStateException("A preset by that name already exists."); + } + for (size_t i = 0; i < presets_.size(); ++i) + { + if (presets_[i]->instanceId() ==instanceId) + { + presets_[i]->preset().name(name); + return true; + } + } + return false; + + } + + BankFileEntry &getItem(int64_t instanceId) + { + for (size_t i = 0; i < presets_.size(); ++i) + { + if (presets_[i]->instanceId() == instanceId) + { + return *(presets_[i].get()); + } + } + throw PiPedalArgumentException("Instance not found."); + } + int64_t deletePreset(int64_t instanceId) { + for (size_t i = 0; i < presets_.size(); ++i) + { + if (presets_[i]->instanceId() == instanceId) + { + presets_.erase(presets_.begin()+i); + int64_t newSelection; + if (i < presets_.size()) + { + newSelection = presets_[i]->instanceId(); + } else if (presets_.size() > 1) { + newSelection = presets_[0]->instanceId(); + } else { + // zero length? We can never have a zero-length bank. + // Add a default preset and make it the selected preset. + PedalBoard pedalBoard = PedalBoard::MakeDefault(); + this->addPreset(pedalBoard); + newSelection = presets_[0]->instanceId(); + } + if (instanceId == this->selectedPreset_) + { + this->selectedPreset_ = newSelection; + } + return newSelection; + } + } + throw PiPedalStateException("Preset not found."); + } + + DECLARE_JSON_MAP(BankFile); +}; + +class BankIndexEntry { + int64_t instanceId_ = 0; + std::string name_; +public: + GETTER_SETTER(instanceId); + GETTER_SETTER_REF(name); + + DECLARE_JSON_MAP(BankIndexEntry); +}; + +class BankIndex { + int64_t selectedBank_ = 0; + int64_t nextInstanceId_ = 0; + std::vector entries_; +public: + GETTER_SETTER(selectedBank); + GETTER_SETTER_VEC(entries); + + DECLARE_JSON_MAP(BankIndex); + + void move(size_t from, size_t to) + { + if (from >= this->entries_.size()) { + throw std::invalid_argument("Argument out of range."); + } + if (to >= this->entries_.size()) { + throw std::invalid_argument("Argument out of range."); + } + BankIndexEntry t = std::move(this->entries_[from]); + entries_.erase(entries_.begin()+from); + entries_.insert(entries_.begin()+to,std::move(t)); + } + + void clear() { + entries_.clear(); + selectedBank_ = 0; + } + int64_t addBank(int64_t afterId,const std::string& name) + { + BankIndexEntry bank; + bank.name(name); + bank.instanceId(++nextInstanceId_); + + for (size_t i = 0; i < this->entries_.size(); ++i) + { + if (entries_[i].instanceId() == afterId) + { + entries_.insert(entries_.begin()+(i+1), bank); + return bank.instanceId(); + } + } + // else at the end. + entries_.push_back(bank); + return bank.instanceId(); + } + BankIndexEntry* getEntryByName(const std::string &name) + { + for (size_t i = 0; i < entries_.size(); ++i) + { + if (entries_[i].name() == name) + { + return &entries_[i]; + } + } + return nullptr; + } + BankIndexEntry&getBankIndexEntry(int64_t instanceId) + { + for (size_t i = 0; i < entries_.size(); ++i) + { + if (entries_[i].instanceId() == instanceId) + { + return entries_[i]; + } + } + throw PiPedalArgumentException("Bank not found."); + } + const BankIndexEntry&getBankIndexEntry(int64_t instanceId) const + { + for (size_t i = 0; i < entries_.size(); ++i) + { + if (entries_[i].instanceId() == instanceId) + { + return entries_[i]; + } + } + throw PiPedalArgumentException("Bank not found."); + } + +}; +#undef GETTER_SETTER +#undef GETTER_SETTER_VEC +#undef GETTER_SETTER_REF + +} + + diff --git a/src/BeastServer.cpp b/src/BeastServer.cpp new file mode 100644 index 0000000..3e29690 --- /dev/null +++ b/src/BeastServer.cpp @@ -0,0 +1,1241 @@ +// +// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +//------------------------------------------------------------------------------ +// +// Example: Advanced server +// +//------------------------------------------------------------------------------ + +#include "pch.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "HtmlHelper.hpp" +#include "Lv2Log.hpp" + +#include "BeastServer.hpp" + +#include "Uri.hpp" + +using namespace pipedal; + +using tcp = boost::asio::ip::tcp; // from +namespace http = boost::beast::http; // from +namespace websocket = boost::beast::websocket; // from + +const size_t MAX_READ_SIZE = 1 * 1024 * 204; +using namespace boost; + +std::string +pipedal::last_modified(const std::filesystem::path &path) +{ + auto cPath = path.c_str(); + + struct stat fStat; + if (stat(cPath, &fStat) == 0) + { + return HtmlHelper::timeToHttpDate(fStat.st_mtim.tv_sec); + } + else + { + return HtmlHelper::timeToHttpDate(0); + } +} + +std::map extensionsToMimeType = { + {".htm", "text/html"}, + {".html", "text/html"}, + {".php", "text/html"}, + {".css", "text/css"}, + {".txt", "text/plain"}, + {".js", "application/javascript"}, + {".json", "application/json"}, + {".xml", "application/xml"}, + {".png", "image/png"}, + {".jpe", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".jpg", "image/jpeg"}, + {".gif", "image/gif"}, + {".bmp", "image/bmp"}, + {".ico", "image/x-icon"}, + {".tiff", "image/tiff"}, + {".tif", "image/tiff"}, + {".svg", "image/svg+xml"}, + {".svgz", "image/svg+xml"}, + +}; +// Return a reasonable mime type based on the extension of a file. +std::string +mime_type(const std::filesystem::path &path) +{ + auto const ext = path.extension(); + try + { + return extensionsToMimeType.at(ext); + } + catch (const std::exception &) + { + return "application/octet-stream"; + } +} + +// Append an HTTP rel-path to a local filesystem path. +// The returned path is normalized for the platform. +std::filesystem::path +path_cat( + boost::beast::string_view base, + const std::vector &segments) +{ + + std::filesystem::path result = base.to_string(); + + for (const std::string &segment : segments) + { + if (segment.find("..") != -1) + { + throw std::invalid_argument("Invalid segment."); + } + if (segment.find('/') != -1) + throw std::invalid_argument("Invalid segment."); + if (segment.find('\\') != -1) + throw std::invalid_argument("Invalid segment."); + if (segment.find('/') != -1) + throw std::invalid_argument("Invalid segment."); + if (segment.find(':') != -1) + throw std::invalid_argument("Invalid segment."); + + result /= segment; + } + return result; +} + +std::string GetFromAddress(const tcp::socket &socket) +{ + std::stringstream s; + s << socket.remote_endpoint().address().to_string() << ':' << socket.remote_endpoint().port(); + return s.str(); +} +// This function produces an HTTP response for the given +// request. The type of the response object depends on the +// contents of the request, so the interface requires the +// caller to pass a generic lambda for receiving the response. +template < + class Body, class Allocator, + class Send> +void handle_request( + const tcp::socket &socket_, + BeastServer *server, + http::request> &&req, + Send &&send) +{ + + + // Returns a bad request response + auto const bad_request = + [&req, &socket_](boost::beast::string_view why) + { + Lv2Log::error("http - (%s) Bad request: %s,", GetFromAddress(socket_).c_str(), why.to_string().c_str()); + http::response res{http::status::bad_request, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::content_type, "text/plain"); + res.keep_alive(req.keep_alive()); + res.body() = why.to_string(); + res.prepare_payload(); + return res; + }; + + // Returns a not found response + auto const not_found = + [&req, &socket_](boost::beast::string_view target) + { + Lv2Log::error("http - (%s) Not found: %s,", GetFromAddress(socket_).c_str(), target.to_string().c_str()); + http::response res{http::status::not_found, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::content_type, "text/plain"); + res.keep_alive(req.keep_alive()); + res.body() = "The resource '" + target.to_string() + "' was not found."; + res.prepare_payload(); + return res; + }; + + // Returns a server error response + auto const server_error = + [&req, &socket_](boost::beast::string_view what) + { + Lv2Log::error("http - (%s) Server error: %s,", GetFromAddress(socket_).c_str(), what.to_string().c_str()); + http::response res{http::status::not_found, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::content_type, "text/plain"); + res.keep_alive(req.keep_alive()); + res.body() = what.to_string(); + res.prepare_payload(); + return res; + }; + + if (server->HasAccessPointGateway()) + { + auto &gateway = server->GetAccessPointGateway(); + auto remoteAddress = socket_.remote_endpoint().address(); + if (remoteAddress.is_v4()) + { + auto v4Address = remoteAddress.to_v4(); + unsigned int gwAddr = (gateway.netmask().to_uint() & gateway.address().to_uint()); + unsigned int ipAddr = (gateway.netmask().to_uint() & v4Address.to_uint()); + + if ((gateway.netmask().to_uint() & gateway.address().to_uint()) == (gateway.netmask().to_uint() & v4Address.to_uint())) + { + std::string host = req[http::field::host].to_string(); + std::string gatewayHost = server->GetAccessPointServerAddress(); + if (host != gatewayHost) + { + + uri requestUri; + requestUri.set(req.target().begin(), req.target().end()); + if (requestUri.segment_count() != 0) { + return send(not_found(req.target())); + } + uri_builder builder(requestUri); + builder.set_authority(gatewayHost); + + std::string redirectUri = builder.str(); + Lv2Log::info("Access point redirect from" + host + " to " + redirectUri); + + + // redirect to the gateway host. + http::response res{http::status::temporary_redirect, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::location, redirectUri); + res.prepare_payload(); + return send(std::move(res)); + + } + } + } + } + + if (req.method() == http::verb::options) + { + http::response res{http::status::no_content, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::access_control_allow_origin, req[http::field::origin]); + res.set(http::field::access_control_allow_methods, "POST, GET, OPTIONS, HEADERS"); + res.set(http::field::access_control_allow_headers, "Content-Type"); + res.keep_alive(req.keep_alive()); + return send(std::move(res)); + } + + uri request_uri; + try + { + request_uri.set(req.target().begin(), req.target().end()); + std::string host = req[http::field::host].to_string(); + int pos = host.find_last_of(':'); + if (pos != std::string::npos) + { + host = host.substr(0, pos); + } + uri_builder builder(request_uri); + builder.set_authority(host); + builder.set_port(socket_.local_endpoint().port()); + // stub: set htts scheme once we implement it. + builder.set_scheme("http"); + + std::string strUri = builder.str(); + request_uri = uri(strUri.c_str()); + } + catch (const std::exception &_) + { + return send((bad_request("Malformed target."))); + } + + for (auto requestHandler : server->RequestHandlers()) + { + + if (requestHandler->wants(req.method(), request_uri)) + { + + if (req.method() == http::verb::head) + { + Lv2Log::info("http - (%s) head %s", GetFromAddress(socket_), request_uri.str().c_str()); + + boost::beast::error_code ec; + http::response res{http::status::ok, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::date, HtmlHelper::timeToHttpDate(time(nullptr))); + res.set(http::field::access_control_allow_origin, req[http::field::origin]); + requestHandler->head_response(request_uri, req, res, ec); + res.keep_alive(req.keep_alive()); + // Handle the case where the file doesn't exist + + if (ec == boost::system::errc::no_such_file_or_directory) + return send(not_found(req.target())); + + if (ec) + { + return send(server_error(ec.message())); + } + req.prepare_payload(); + return send(std::move(res)); + } + else if (req.method() == http::verb::get) + { + if (server->LogHttpRequests()) + { + Lv2Log::info("http - (%s) get %s", GetFromAddress(socket_).c_str(), request_uri.str().c_str()); + } + + boost::beast::error_code ec; + http::response res{http::status::ok, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::date, HtmlHelper::timeToHttpDate(time(nullptr))); + res.set(http::field::access_control_allow_origin, req[http::field::origin]); + requestHandler->get_response(request_uri, req, res, ec); + res.keep_alive(req.keep_alive()); + if (ec == boost::system::errc::no_such_file_or_directory) + return send(not_found(req.target())); + + if (ec) + { + return send(server_error(ec.message())); + } + req.prepare_payload(); + return send(std::move(res)); + } + else if (req.method() == http::verb::post) + { + if (server->LogHttpRequests()) + { + Lv2Log::info("http - (%s) post %s", GetFromAddress(socket_).c_str(), request_uri.str().c_str()); + } + + boost::beast::error_code ec; + http::response res{http::status::ok, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::date, HtmlHelper::timeToHttpDate(time(nullptr))); + res.set(http::field::access_control_allow_origin, req[http::field::origin]); + requestHandler->post_response(request_uri, req, res, ec); + res.keep_alive(req.keep_alive()); + if (ec == boost::system::errc::no_such_file_or_directory) + return send(not_found(req.target())); + + if (ec) + { + return send(server_error(ec.message())); + } + req.prepare_payload(); + return send(std::move(res)); + } + return send(bad_request("Unknown HTTP-method")); + } + } + // Make sure we can handle the method + if (req.method() != http::verb::get && + req.method() != http::verb::head) + return send(bad_request("Unknown HTTP-method")); + + // Request path must be absolute and not contain "..". + if (req.target().empty() || + req.target()[0] != '/' || + req.target().find("..") != boost::beast::string_view::npos) + return send(not_found(req.target())); // security: report not found to avoid disclosing info. + + // Build the path to the requested file + auto path = path_cat(server->GetDocRoot().c_str(), request_uri.segments()); + if (req.target().back() == '/' || req.target().size() == 0) + path /= "index.html"; + + // Attempt to open the file + boost::beast::error_code ec; + http::file_body::value_type body; + body.open(path.c_str(), boost::beast::file_mode::scan, ec); + + // Handle the case where the file doesn't exist + if (ec == boost::system::errc::no_such_file_or_directory) + return send(not_found(req.target())); + + // Handle an unknown error + if (ec) + return send(server_error(ec.message())); + + // Respond to HEAD request + if (req.method() == http::verb::head) + { + if (server->LogHttpRequests()) + { + Lv2Log::info("http - (%s) head %s", GetFromAddress(socket_).c_str(), request_uri.str().c_str()); + } + + http::response res{http::status::ok, req.version()}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::date, HtmlHelper::timeToHttpDate(time(nullptr))); + res.set(http::field::content_type, mime_type(path)); + res.set(http::field::last_modified, last_modified(path)); + res.content_length(body.size()); + res.keep_alive(req.keep_alive()); + return send(std::move(res)); + } + else if (req.method() == http::verb::get) + { + if (server->LogHttpRequests()) + { + Lv2Log::info("http - (%s) get %s", GetFromAddress(socket_).c_str(), request_uri.str().c_str()); + } + + // Respond to GET request + http::response res{ + std::piecewise_construct, + std::make_tuple(std::move(body)), + std::make_tuple(http::status::ok, req.version())}; + res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(http::field::date, HtmlHelper::timeToHttpDate(time(nullptr))); + res.set(http::field::content_type, mime_type(path)); + res.set(http::field::last_modified, last_modified(path)); + res.content_length(body.size()); + res.keep_alive(req.keep_alive()); + return send(std::move(res)); + } + else + { + return send(bad_request("Unknown HTTP-method")); + } +} + +//------------------------------------------------------------------------------ + +// Echoes back all received WebSocket messages +class websocket_session : public std::enable_shared_from_this, private SocketHandler::IWriteCallback +{ + websocket::stream ws_; + boost::asio::strand< + boost::asio::io_context::executor_type> + strand_; + boost::asio::steady_timer timer_; + boost::beast::multi_buffer read_buffer_; + boost::beast::multi_buffer write_buffer_; + + BeastServer *beastServer_; + std::shared_ptr socket_handler_; + + std::queue writeQueue; + + bool writePending = false; + ; + std::mutex writeQueueMutex; + std::string fromAddress; + +public: + ~websocket_session() + { + Lv2Log::info("http - (%s) Websocket closed.", fromAddress.c_str()); + } + virtual void close() + { + this->ws_.close(websocket::close_reason()); + } + virtual void writeCallback(const std::string &text) + { + { + std::lock_guard guard(writeQueueMutex); + if (writePending) + { + writeQueue.push(text); + return; + } + writePending = true; + } + do_write(text); + } + void do_write(const std::string &text) + { + size_t n = buffer_copy(write_buffer_.prepare(text.size()), boost::asio::buffer(text)); + write_buffer_.commit(n); + ws_.text(true); + + ws_.async_write( + write_buffer_.data(), + boost::asio::bind_executor( + strand_, + std::bind( + &websocket_session::on_write, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2))); + } + // Take ownership of the socket + explicit websocket_session( + const std::string &fromAddress, + BeastServer *beastServer, + std::shared_ptr &&socketHandler, + tcp::socket socket) + : beastServer_(beastServer), socket_handler_(socketHandler), + fromAddress(fromAddress), + ws_(std::move(socket)), + strand_(ws_.get_executor()), + read_buffer_(MAX_READ_SIZE), + timer_(ws_.get_executor().context(), + (std::chrono::steady_clock::time_point::max)()) + { + } + + // Start the asynchronous operation + template + void + run(http::request> req) + { + // Run the timer. The timer is operated + // continuously, this simplifies the code. + on_timer({}); + + // Set the timer + timer_.expires_after(std::chrono::seconds(15)); + // Accept the websocket handshake + + ws_.async_accept( + req, + boost::asio::bind_executor( + strand_, + std::bind( + &websocket_session::on_accept, + shared_from_this(), + std::placeholders::_1))); + } + + // Called when the timer expires. + void + on_timer(boost::system::error_code ec) + { + if (ec && ec != boost::asio::error::operation_aborted) + this->beastServer_->onError(ec, "timer"); + return; + + // Verify that the timer really expired since the deadline may have moved. + if (timer_.expiry() <= std::chrono::steady_clock::now()) + { + // Closing the socket cancels all outstanding operations. They + // will complete with boost::asio::error::operation_aborted + ws_.next_layer().shutdown(tcp::socket::shutdown_both, ec); + ws_.next_layer().close(ec); + return; + } + + // Wait on the timer + timer_.async_wait( + boost::asio::bind_executor( + strand_, + std::bind( + &websocket_session::on_timer, + shared_from_this(), + std::placeholders::_1))); + } + + void + on_accept(boost::system::error_code ec) + { + // Happens when the timer closes the socket + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec) + { + beastServer_->onError(ec, "accept"); + return; + } + if (socket_handler_) + { + auto t = socket_handler_.get(); + t->setWriteCallback(this); + socket_handler_->onAttach(); + } + + // Read a message + do_read(); + } + + void + do_read() + { + // Set the timer + timer_.expires_after(std::chrono::seconds(15)); + + // Read a message into our buffer + ws_.async_read( + read_buffer_, + boost::asio::bind_executor( + strand_, + std::bind( + &websocket_session::on_read, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2))); + } + + void + on_read( + boost::system::error_code ec, + std::size_t bytes_transferred) + { + + // Happens when the timer closes the socket + if (ec == boost::asio::error::operation_aborted) + return; + + // This indicates that the websocket_session was closed + if (ec == websocket::error::closed) + return; + + if (ec) + { + beastServer_->onError(ec, "read"); + return; + } + + // Echo the message + if (ws_.got_text()) + { + std::string data(beast::buffers_to_string(read_buffer_.data())); + this->socket_handler_->onReceive(data); + read_buffer_.consume(bytes_transferred); + } + else + { + read_buffer_.consume(bytes_transferred); // ignore binary messages + } + + do_read(); + // ws_.text(ws_.got_text()); + // ws_.async_write( + // buffer_.data(), + // boost::asio::bind_executor( + // strand_, + // std::bind( + // &websocket_session::on_write, + // shared_from_this(), + // std::placeholders::_1, + // std::placeholders::_2))); + } + + void fail(boost::system::error_code ec, const char *what) + { + beastServer_->onError(ec, what); + } + void + on_write( + boost::system::error_code ec, + std::size_t bytes_transferred) + { + boost::ignore_unused(bytes_transferred); + + // Happens when the timer closes the socket + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec) + { + fail(ec, "write"); + } + + // Clear the buffer + std::string nextWrite; + write_buffer_.consume(write_buffer_.size()); + + { + std::lock_guard guard(this->writeQueueMutex); + if (writeQueue.size() != 0) + { + nextWrite = writeQueue.front(); + writeQueue.pop(); + } + else + { + writePending = false; + return; + } + } + do_write(nextWrite); + } +}; + +// Handles an HTTP server connection +class http_session : public std::enable_shared_from_this +{ + // This queue is used for HTTP pipelining. + class queue + { + enum + { + // Maximum number of responses we will queue + limit = 8 + }; + + // The type-erased, saved work item + struct work + { + virtual ~work() = default; + virtual void operator()() = 0; + }; + + http_session &self_; + std::vector> items_; + + public: + explicit queue(http_session &self) + : self_(self) + { + static_assert(limit > 0, "queue limit must be positive"); + items_.reserve(limit); + } + + // Returns `true` if we have reached the queue limit + bool + is_full() const + { + return items_.size() >= limit; + } + + // Called when a message finishes sending + // Returns `true` if the caller should initiate a read + bool + on_write() + { + BOOST_ASSERT(!items_.empty()); + auto const was_full = is_full(); + items_.erase(items_.begin()); + if (!items_.empty()) + (*items_.front())(); + return was_full; + } + + // Called by the HTTP handler to send a response. + template + void + operator()(http::message &&msg) + { + // This holds a work item + struct work_impl : work + { + http_session &self_; + http::message msg_; + + work_impl( + http_session &self, + http::message &&msg) + : self_(self), msg_(std::move(msg)) + { + } + + void + operator()() + { + http::async_write( + self_.socket_, + msg_, + boost::asio::bind_executor( + self_.strand_, + std::bind( + &http_session::on_write, + self_.shared_from_this(), + std::placeholders::_1, + msg_.need_eof()))); + } + }; + + // Allocate and store the work + items_.emplace_back(new work_impl(self_, std::move(msg))); + + // If there was no previous work, start this one + if (items_.size() == 1) + (*items_.front())(); + } + }; + + tcp::socket socket_; + boost::asio::strand< + boost::asio::io_context::executor_type> + strand_; + boost::asio::steady_timer timer_; + boost::beast::flat_buffer buffer_; + http::request req_; + queue queue_; + BeastServer *beastServer_; + +public: + // Take ownership of the socket + explicit http_session( + BeastServer *beastServer, + tcp::socket socket) + : beastServer_(beastServer), socket_(std::move(socket)), strand_(socket_.get_executor()), timer_(socket_.get_executor().context(), + (std::chrono::steady_clock::time_point::max)()), + queue_(*this) + { + } + + // Start the asynchronous operation + void + run() + { + // Run the timer. The timer is operated + // continuously, this simplifies the code. + on_timer({}); + + do_read(); + } + + void + do_read() + { + // Set the timer + timer_.expires_after(std::chrono::seconds(15)); + + // Read a request + http::async_read(socket_, buffer_, req_, + boost::asio::bind_executor( + strand_, + std::bind( + &http_session::on_read, + shared_from_this(), + std::placeholders::_1))); + } + + // Called when the timer expires. + void + on_timer(boost::system::error_code ec) + { + if (ec && ec != boost::asio::error::operation_aborted) + return fail(ec, "timer"); + + // Verify that the timer really expired since the deadline may have moved. + if (timer_.expiry() <= std::chrono::steady_clock::now()) + { + // Closing the socket cancels all outstanding operations. They + // will complete with boost::asio::error::operation_aborted + if (!beastServer_->Stopping()) + { + socket_.shutdown(tcp::socket::shutdown_both, ec); + } + socket_.close(ec); + return; + } + + // Wait on the timer + timer_.async_wait( + boost::asio::bind_executor( + strand_, + std::bind( + &http_session::on_timer, + shared_from_this(), + std::placeholders::_1))); + } + + void fail(boost::system::error_code ec, const char *what) + { + beastServer_->onError(ec, what); + } + + void + on_read(boost::system::error_code ec) + { + // Happens when the timer closes the socket + if (ec == boost::asio::error::operation_aborted) + return; + + // This means they closed the connection + if (ec == http::error::end_of_stream) + return do_close(); + + if (ec) + { + fail(ec, "read"); + return; + } + // See if it is a WebSocket Upgrade + if (websocket::is_upgrade(req_)) + { + uri request_uri; + try + { + request_uri.set(req_.target().begin(), req_.target().end()); + } + catch (const std::exception &_) + { + fail(ec, "socket uri"); + return; + } + + std::shared_ptr socketFactory = beastServer_->GetSocketFactory(request_uri); + if (!socketFactory) + { + fail(http::error::bad_target, "Not found"); + return; + } + + Lv2Log::info("http - (%s) Websocket opened: %s", GetFromAddress(socket_).c_str(), request_uri.str().c_str()); + // Create a WebSocket websocket_session by transferring the socket + std::string fromName = GetFromAddress(socket_); + std::make_shared( + fromName, + this->beastServer_, + socketFactory ? socketFactory->CreateHandler(request_uri) : nullptr, + std::move(socket_)) + ->run(std::move(req_)); + return; + } + // Send the response + handle_request( + this->socket_, + beastServer_, + std::move(req_), + queue_); + + // If we aren't at the queue limit, try to pipeline another request + if (!queue_.is_full()) + do_read(); + } + + void + on_write(boost::system::error_code ec, bool close) + { + // Happens when the timer closes the socket + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec) + return fail(ec, "write"); + + if (close) + { + // This means we should close the connection, usually because + // the response indicated the "Connection: close" semantic. + return do_close(); + } + + // Inform the queue that a write completed + if (queue_.on_write()) + { + // Read another request + do_read(); + } + } + + void + do_close() + { + // Send a TCP shutdown + boost::system::error_code ec; + if (!beastServer_->Stopping()) + { + socket_.shutdown(tcp::socket::shutdown_send, ec); + } + socket_.close(); + + + } +}; + +//------------------------------------------------------------------------------ + +// Accepts incoming connections and launches the sessions +class listener : public std::enable_shared_from_this +{ + tcp::acceptor acceptor_; + tcp::socket socket_; + BeastServer *beastServer_; + +public: + ~listener() + { + beastServer_->onListenerClosed(); + } + listener( + BeastServer *server, + boost::asio::io_context &ioc, + tcp::endpoint endpoint) + : beastServer_(server), acceptor_(ioc), socket_(ioc) + { + boost::system::error_code ec; + + // Open the acceptor + acceptor_.open(endpoint.protocol(), ec); + if (ec) + { + fail(ec, "open"); + return; + } + + boost::asio::socket_base::reuse_address option(true); + acceptor_.set_option(option); + // Lv2Log::warning("http - Accepting connections with reuse_adddress to allow faster debug turns. Should NOT be enabled in production use. "); + + // Leftover client sockets in TIME_WAIT state prevent binding of the server address. + // Retry for up to 140 seconds in order to allow the TIME_WAIT sockets to expire. + // If we still can't establish a connection, we can be sure that somebody else or an existing instance is servicing the address, so + // quit after that. + int retries = 0; + int retryTime = 1; + int totalRetryTime = 0; + int MAX_RETRY_TIME = 240; // socket-timeout-ish. + + while (true) + { + // Bind to the server address + acceptor_.bind(endpoint, ec); + if (!ec) + { + break; + } + else + { + ++retries; + if (totalRetryTime > MAX_RETRY_TIME) + { + fail(ec, "bind"); + return; + } + Lv2Log::info("http - bind: %s. (port %d) Retrying...", ec.message().c_str(), endpoint.port()); + sleep(retryTime); + retryTime *= 2; + if (retryTime > 10) + retryTime = 10; + totalRetryTime += retryTime; + } + } + + Lv2Log::info("http - Server listening on %s:%d", endpoint.address().to_string().c_str(), (int)endpoint.port()); + + // Start listening for connections + acceptor_.listen( + boost::asio::socket_base::max_listen_connections, ec); + if (ec) + { + fail(ec, "listen"); + return; + } + } + + void + stop() + { + acceptor_.cancel(); + } + + // Start accepting incoming connections + void + run() + { + if (!acceptor_.is_open()) + return; + do_accept(); + } + + void + do_accept() + { + acceptor_.async_accept( + socket_, + std::bind( + &listener::on_accept, + shared_from_this(), + std::placeholders::_1)); + } + + void fail(boost::system::error_code ec, const char *what) + { + beastServer_->onError(ec, what); + } + void + on_accept(boost::system::error_code ec) + { + if (ec) + { + fail(ec, "accept"); + return; + } + else + { + // Create the http_session and run it + std::make_shared( + beastServer_, + std::move(socket_)) + ->run(); + } + + // Accept another connection + do_accept(); + } +}; + +//------------------------------------------------------------------------------ + +BeastServer::BeastServer(const boost::asio::ip::address &address, int port, const char *rootPath, int threads) + : address(address), + port((unsigned short)port), + doc_root(rootPath), + threads(threads), + pBgThread(nullptr) +{ +} + +void BeastServer::Stop() +{ + if (stopping) return; + stopping = true; + listener *p = nullptr; + { + std::unique_lock lk(io_mutex); + p = (listener*)this->pListener; + this->pListener = nullptr; + } + if (p != nullptr) + { + p->stop(); + } + boost::asio::io_context *pIoContext = nullptr; + { + std::unique_lock lk(io_mutex); + pIoContext = this->pIoContext; + this->pIoContext = nullptr; + } + if (pIoContext != nullptr) + { + pIoContext->stop(); + }; +} + +void BeastServer::onListenerClosed() +{ + std::unique_lock lk(io_mutex); + this->pListener = nullptr; +} + +static void ThreadProc(BeastServer *server) +{ + server->Run(); +} + +void BeastServer::RunInBackground() +{ + if (this->pBgThread != nullptr) + { + throw std::runtime_error("Bad state."); + } + this->pBgThread = new std::thread(ThreadProc, this); +} + +void BeastServer::Join() +{ + if (this->pBgThread != nullptr) + { + Stop(); + this->pBgThread->join(); + this->pBgThread = nullptr; + } +} + +void BeastServer::Run() +{ + // The io_context is required for all I/O + boost::asio::io_context ioc{threads}; + + { + // save a reference for use by stop() + std::unique_lock lk(io_mutex); + pIoContext = &ioc; + } + + // Create and launch a listening port + std::shared_ptr listenerInstance = std::make_shared( + this, + ioc, + tcp::endpoint{address, port}); + listenerInstance->run(); + + // save a reference for use by stop() + { + std::unique_lock lk(io_mutex); + this->pListener = (void *)&(*listenerInstance); + } + + // Run the I/O service on the requested number of threads + std::vector v; + v.reserve(threads - 1); + for (auto i = threads - 1; i > 0; --i) + v.emplace_back( + [&ioc] + { + ioc.run(); + }); + ioc.run(); + + ioc.stop(); + for (auto &thread : v) + { + thread.join(); + } + { + std::unique_lock lk(io_mutex); + this->pListener = nullptr; + this->pIoContext = nullptr; + } +} + +BeastServer::~BeastServer() +{ + // Shutdown if running in background. + Stop(); + Join(); +} + +void BeastServer::onWarning(boost::system::error_code ec, char const *what) +{ + std::stringstream s; + s << "http - " << what << ": " << ec.message() << " (" << ec.value() << ')'; + Lv2Log::warning(s.str().c_str()); +} +void BeastServer::onInfo(char const *message) +{ + Lv2Log::info("%s", message); +} + +void BeastServer::onError(boost::system::error_code ec, char const *what) +{ + std::stringstream s; + s << "http - " << what << ": " << ec.message() << " (" << ec.value() << ')'; + Lv2Log::warning(s.str().c_str()); +} + +std::shared_ptr BeastServer::GetSocketFactory(const uri &request_uri) +{ + for (auto factory : this->socket_factories) + { + if (factory->wants(request_uri)) + { + return factory; + } + } + return nullptr; +} diff --git a/src/BeastServer.hpp b/src/BeastServer.hpp new file mode 100644 index 0000000..9759c02 --- /dev/null +++ b/src/BeastServer.hpp @@ -0,0 +1,208 @@ +#pragma once +#include +#include +#include + +#include +#include +#include "Uri.hpp" +#include +#include + + +// forward declaration. + +class websocket_session; + +namespace pipedal { +using HttpRequest =boost::beast::http::request; + + +std::string last_modified(const std::filesystem::path& path); + +class SocketHandler { +public: + + class IWriteCallback { + public: + virtual void close() = 0; + + virtual void writeCallback(const std::string& text) = 0; + }; + +private: + friend class ::websocket_session; + + + IWriteCallback *writeCallback_; + + void setWriteCallback(IWriteCallback *writeCallback) { + writeCallback_ = writeCallback; + } + +protected: + virtual void onReceive(const std::string_view&text) = 0; +public: + void receive(const std::string_view&text) { + onReceive(text); + } + void send(const std::string &text) { + if (writeCallback_ != nullptr) + { + writeCallback_->writeCallback(text); + } + } + virtual void Close() + { + writeCallback_->close(); + } + + virtual ~SocketHandler() = default; + + virtual void onAttach() { } + +}; + +class ISocketFactory { +public: + virtual bool wants(const uri &request) = 0; + virtual std::shared_ptr CreateHandler(const uri& request) = 0; +}; + +class RequestHandler { +private: + uri target_url_; +public: + RequestHandler(const char*target_url) + : target_url_(target_url) + { + + } + ~RequestHandler() = default; + + virtual bool wantsRedirect(const uri& requestUri) + { + return false; + } + uri GetRedirect(const uri& requestUri) + { + return requestUri; + } + + virtual bool wants(boost::beast::http::verb verb,const uri &request_uri) const { + if (request_uri.segment_count() < target_url_.segment_count()) + { + return false; + } + for (int i = 0; i < target_url_.segment_count(); ++i) + { + if (request_uri.segment(i) != target_url_.segment(i)) + { + return false; + } + } + return true; + } + + virtual void head_response( + const uri&request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) = 0; + + virtual void get_response( + const uri&request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) = 0; + + virtual void post_response( + const uri&request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + get_response(request_uri,req,res,ec); + } + + +}; +class BeastServer { +private: + boost::asio::ip::address address; + unsigned short port; + std::string doc_root; + int threads; + std::mutex log_mutex; + std::vector > request_handlers; + std::vector > socket_factories; + std::mutex io_mutex; + boost::asio::io_context *pIoContext = nullptr; + void*pListener = nullptr; + std::thread*pBgThread = nullptr; + + bool logHttpRequests = false; + + bool hasAccessPointGateway = false; + boost::asio::ip::network_v4 accessPointGateway; + std::string accessPointServerAddress; + bool stopping = false; + + +public: + + BeastServer( + const boost::asio::ip::address& address, + int port, + const char*rootPath, + int threads = 10); + + void Run(); + void RunInBackground(); + bool Stopping() const { return this->stopping; } + void Stop(); + void Join(); + + void SetLogHttpRequests(bool logRequests) { this->logHttpRequests = logRequests; } + bool LogHttpRequests() const { return this->logHttpRequests; } + boost::asio::io_context& IoContext() { + return *pIoContext; + } + + void AddRequestHandler(std::shared_ptr requestHandler) + { + request_handlers.push_back(requestHandler); + } + + void AddSocketFactory(const std::shared_ptr &socketHandler) + { + socket_factories.push_back(socketHandler); + } + + std::vector > &RequestHandlers() { return request_handlers; } + + const std::string&GetDocRoot() { return doc_root; } + + virtual ~BeastServer(); + + std::shared_ptr GetSocketFactory(const uri &request_uri); + + void SetAccessPointGateway(const boost::asio::ip::network_v4 &gateway, const std::string&accessPointServerAddress) + { + this->accessPointGateway = gateway; + this->hasAccessPointGateway = true; + this->accessPointServerAddress = accessPointServerAddress; + } + bool HasAccessPointGateway() const { return hasAccessPointGateway; } + boost::asio::ip::network_v4 &GetAccessPointGateway() { return this->accessPointGateway; } + const std::string & GetAccessPointServerAddress() const { return this->accessPointServerAddress; } + +public: + virtual void onError(boost::system::error_code ec, char const* what); + virtual void onWarning(boost::system::error_code ec, char const* what); + virtual void onInfo(char const* what); + + virtual void onListenerClosed(); +}; + +} // namespace pipedal; \ No newline at end of file diff --git a/src/BufferPool.hpp b/src/BufferPool.hpp new file mode 100644 index 0000000..305bc3c --- /dev/null +++ b/src/BufferPool.hpp @@ -0,0 +1,43 @@ +#pragma once + + + +#include +// maintains ownership of allocated buffers. + +namespace pipedal { + + +class BufferPool { + std::vector allocatedBuffers; + +public: + ~BufferPool() { + Clear(); + } + template + TYPE *AllocateBuffer(size_t size) + { + TYPE *result= new TYPE[size]; + for (int i = 0; i < size; ++i) + { + result[i] = 0; + } + allocatedBuffers.push_back(result); + return result; + } + + void Clear() { + for (int i = 0; i < allocatedBuffers.size(); ++i) + { + delete[] (char*)allocatedBuffers[i]; + } + allocatedBuffers.resize(0); + } + + +}; + + + +} // namespace. \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..ee275a2 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,136 @@ +set(VERBOSE true) +cmake_minimum_required(VERSION 3.19.0) + + +include(FindPkgConfig) + + +pkg_check_modules(SYSTEMD "systemd") +if(!SYSTEMD_FOUND) + message(ERROR "libsystemd-dev package not installed.") +else() + message(STATUS "SYSTEMD_LIBRARIES: ${SYSTEMD_LIBRARIES}") + message(STATUS "SYSTEMD_INCLUDE_DIRS: ${SYSTEMD_INCLUDE_DIRS}") +endif() + + +pkg_check_modules(LILV_0 "lilv-0") +if(!LILV_0_FOUND) + message(ERROR "lilv-0 package not installed.") +else() + message(STATUS "LILV_0_LIBRARIES: ${LILV_0_LIBRARIES}") + message(STATUS "LILV_0_INCLUDE_DIRS: ${LILV_0_INCLUDE_DIRS}") +endif() + +pkg_check_modules(JACK "jack") +if(!JACK_FOUND) + message(ERROR "jack package not installed.") +else() + message(STATUS "JACK_LIBRARIES: ${JACK_LIBRARIES}") + message(STATUS "JACK_INCLUDE_DIRS: ${JACK_INCLUDE_DIRS}") +endif() + + +# specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if (CMAKE_BUILD_TYPE MATCHES Debug) + message(STATUS "Debug build") + + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-Wno-psabi -fsanitize=address -static-libasan -O0 -DDEBUG" ) +elseif(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + message(STATUS "RelWithgDebInfo build") + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-Wno-psabi" ) +else() + message(STATUS "Release build") + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-Wno-psabi" ) +endif() + + +# message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") +# set(CMAKE_ENABLE_EXPORTS 1) + +message (STATUS "Cxx flags: ${CMAKE_CXX_FLAGS}" ) + +add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY) + +add_executable(pipedald BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp + RequestHandler.hpp main.cpp json.cpp json.hpp Scratch.cpp Lv2Host.hpp Lv2Host.cpp + PluginType.hpp PluginType.cpp + Lv2Log.hpp Lv2Log.cpp + PiPedalSocket.hpp PiPedalSocket.cpp + PiPedalVersion.hpp PiPedalVersion.cpp + PiPedalModel.hpp PiPedalModel.cpp + PedalBoard.hpp PedalBoard.cpp + Presets.hpp Presets.cpp + Storage.hpp Storage.cpp + Banks.hpp Banks.cpp + JackHost.hpp JackHost.cpp + JackConfiguration.hpp JackConfiguration.cpp + defer.hpp + Lv2Effect.cpp Lv2Effect.hpp + Lv2PedalBoard.cpp Lv2PedalBoard.hpp + BufferPool.hpp + SplitEffect.hpp SplitEffect.cpp + RingBufferReader.hpp + MapFeature.hpp MapFeature.cpp + LogFeature.hpp LogFeature.cpp + Worker.hpp Worker.cpp + OptionsFeature.hpp OptionsFeature.cpp + VuUpdate.hpp VuUpdate.cpp + asan_options.cpp + Units.hpp Units.cpp + RingBuffer.hpp + PiPedalConfiguration.hpp PiPedalConfiguration.cpp + Shutdown.hpp + CommandLineParser.hpp + Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp + JackServerSettings.hpp JackServerSettings.cpp + ShutdownClient.hpp ShutdownClient.cpp + MidiBinding.hpp MidiBinding.cpp + PiPedalMath.hpp + Locale.hpp Locale.cpp + Lv2EventBufferWriter.hpp Lv2EventBufferWriter.cpp + IpSubnet.hpp + ) + +configure_file(config.hpp.in config.hpp) +include_directories( ${PiPedal_SOURCE_DIR}/. ../build/src) + +target_precompile_headers(pipedald PRIVATE pch.h) + + +target_include_directories(pipedald PRIVATE + ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${SYSTEMD_INCLUDE_DIRS} + ) + +target_link_libraries(pipedald PRIVATE pthread atomic stdc++fs + ${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${SYSTEMD_LIBRARIES} systemd + ) +#target_link_libraries(pipedald boost_system) + + +add_executable(pipedalconfig json.cpp json.hpp + HtmlHelper.cpp HtmlHelper.hpp + CommandLineParser.hpp + WriteTemplateFile.hpp WriteTemplateFile.cpp + PiPedalException.hpp + ConfigMain.cpp +) + +target_link_libraries(pipedalconfig PRIVATE pthread atomic stdc++fs + ) + +add_executable(pipedalshutdownd ShutdownMain.cpp CommandLineParser.hpp + JackServerSettings.hpp JackServerSettings.cpp + json.hpp json.cpp HtmlHelper.hpp HtmlHelper.cpp Lv2Log.hpp Lv2Log.cpp + Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp + ) +target_link_libraries(pipedalshutdownd PRIVATE pthread atomic stdc++fs systemd) + + +install (TARGETS pipedalconfig pipedald pipedalshutdownd DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + EXPORT pipedalTargets) + + diff --git a/src/CommandLineParser.hpp b/src/CommandLineParser.hpp new file mode 100644 index 0000000..f65a216 --- /dev/null +++ b/src/CommandLineParser.hpp @@ -0,0 +1,177 @@ +#pragma once +#include +#include +#include "PiPedalException.hpp" +#include + +namespace pipedal +{ + + class CommandLineParser + { + private: + class OptionBase + { + std::string option; + + public: + OptionBase(const std::string &option_) + : option(option_) + { + } + virtual ~OptionBase() + { + } + + protected: + const std::string &GetName() const { return option; } + + public: + bool Matches(const std::string &text) const + { + return option == text; + } + virtual int Execute(int argcRemaining, const char **argvRemaining) = 0; + }; + std::vector options; + + class BooleanOption : public OptionBase + { + + bool *pOutput; + bool value; + + public: + BooleanOption(const std::string &name, bool *pOutput, bool value) + : OptionBase(name), + pOutput(pOutput), + value(value) + { + } + virtual int Execute(int argcRemaining, const char **argvRemaining) + { + *pOutput = value; + return 0; + } + }; + + template + class Option : public OptionBase + { + + T *pOutput; + + public: + Option(const std::string &name, T *pOutput) + : OptionBase(name), + pOutput(pOutput) + { + } + virtual int Execute(int argcRemaining, const char **argvRemaining) + { + if (argcRemaining == 0) + { + throw PiPedalException("Expecting a parameter for option " + GetName()); + } + std::stringstream s(argvRemaining[0]); + try + { + s >> *pOutput; + if (s.fail() || !s.eof()) + { + throw std::exception(); + } + } + catch (const std::exception &e) + { + throw PiPedalException("Argument for option " + GetName() + " is not in the correct format."); + } + return 1; // consumed one argument. + } + }; + + class StringOption : public OptionBase + { + + std::string name; + std::string *pOutput; + + public: + StringOption(const std::string &name, std::string *pOutput) + : OptionBase(name), + pOutput(pOutput) + { + } + virtual int Execute(int argcRemaining, const char **argvRemaining) + { + if (argcRemaining == 0 || argvRemaining[0][0] == '-') + { + throw PiPedalException("Expecting a parameter for option " + GetName()); + } + *pOutput = argvRemaining[0]; + return 1; + } + }; + + int ProcessOption(const std::string &text, int argsRemaining, const char *argv[]) + { + for (auto option : options) + { + if (option->Matches(text)) + { + return option->Execute(argsRemaining, argv); + } + } + std::stringstream s; + s << "Invalid option: " << text; + throw PiPedalException(s.str()); + } + + std::vector args; + + public: + ~CommandLineParser() + { + for (auto item : options) + { + delete item; + } + } + + void AddOption(const std::string &option, bool *pResult) + { + options.push_back(new BooleanOption(option, pResult, true)); + options.push_back(new BooleanOption(option + "+", pResult, true)); + options.push_back(new BooleanOption(option + "-", pResult, false)); + } + void AddOption(const std::string &option, std::string *pResult) + { + options.push_back(new StringOption(option, pResult)); + } + template + void AddOption(const std::string &option, T *pResult) + { + options.push_back(new Option(option, pResult)); + } + bool Parse(int argc, const char *argv[]) + { + for (int i = 1; i < argc; ++i) + { + const char *arg = argv[i]; + if (arg[0] == '-') + { + int argsConsumed = ProcessOption(arg, argc - i - 1, argv + i + 1); + i += argsConsumed; + } + else + { + args.push_back(std::string(arg)); + } + } + return true; + } + + const std::vector Arguments() { return args; } + }; + +} // namespace \ No newline at end of file diff --git a/src/ConfigMain.cpp b/src/ConfigMain.cpp new file mode 100644 index 0000000..56a04c6 --- /dev/null +++ b/src/ConfigMain.cpp @@ -0,0 +1,387 @@ +#include +#include "CommandLineParser.hpp" +#include "PiPedalException.hpp" +#include +#include +#include "WriteTemplateFile.hpp" +#include + +using namespace std; +using namespace pipedal; + +#define SERVICE_ACCOUNT_NAME "pipedal_d" +#define SERVICE_GROUP_NAME "pipedal_d" + +#define SERVICE_PATH "/usr/lib/systemd/system" +#define NATIVE_SERVICE "pipedald" +#define SHUTDOWN_SERVICE "pipedalshutdownd" +// #define REACT_SERVICE "pipedal_react" + +bool exec(std::stringstream &s) +{ + return system(s.str().c_str()) == EXIT_SUCCESS; +} + +std::filesystem::path GetServiceFileName(const std::string &serviceName) +{ + return std::filesystem::path(SERVICE_PATH) / (serviceName + ".service"); +} + +std::filesystem::path findOnPath(const std::string &command) +{ + std::string path = getenv("PATH"); + std::vector paths; + size_t t = 0; + while (t < path.length()) + { + size_t pos = path.find(':', t); + if (pos == string::npos) + { + pos = path.length(); + } + std::string thisPath = path.substr(t, pos - t); + std::filesystem::path path = std::filesystem::path(thisPath) / command; + if (std::filesystem::exists(path)) + { + return path; + } + t = pos + 1; + } + std::stringstream s; + s << "'" << command << "' is not installed."; + throw PiPedalException(s.str()); +} + +void EnableService() +{ + if (system("systemctl enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + { + cout << "Error: Failed to enable the " NATIVE_SERVICE " service."; + } + if (system("systemctl enable " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS) + { + cout << "Error: Failed to enable the " SHUTDOWN_SERVICE " service."; + } +} +void DisableService() +{ + if (system("systemctl disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + { + cout << "Error: Failed to disable the " NATIVE_SERVICE " service."; + } + if (system("systemctl disable " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS) + { + cout << "Error: Failed to disable the " SHUTDOWN_SERVICE " service."; + } +} + +void StopService() +{ + if (system("systemctl stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + { + cout << "Error: Failed to stop the " NATIVE_SERVICE " service."; + } + if (system("systemctl stop " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS) + { + cout << "Error: Failed to stop the " SHUTDOWN_SERVICE " service."; + } +} +void StartService() +{ + + if (system("systemctl start " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + { + throw PiPedalException("Failed to start the " NATIVE_SERVICE " service."); + } + if (system("systemctl start " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS) + { + throw PiPedalException("Failed to start the " SHUTDOWN_SERVICE " service."); + } +} +void RestartService() +{ + + StopService(); + StartService(); +} + +void Install(const std::filesystem::path &programPrefix, const std::string endpointAddress) +{ + auto endpos = endpointAddress.find_last_of(':'); + if (endpos == string::npos) + { + throw PiPedalException("Invalid endpoint address: " + endpointAddress); + } + uint16_t port; + auto strPort = endpointAddress.substr(endpos + 1); + try + { + auto lport = std::stoul(strPort); + if (lport == 0 || lport >= std::numeric_limits::max()) + { + throw PiPedalException("out of range."); + } + port = (uint16_t)lport; + std::stringstream s; + s << port; + strPort = s.str(); // normalized. + } + catch (const std::exception &) + { + std::stringstream s; + s << "Invalid port number: " << strPort; + throw PiPedalException(s.str()); + } + + bool authBindRequired = port < 512; + + // Create and configur service account. + + if (system("groupadd -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS) + { + throw PiPedalException("Failed to create service group."); + } + if (system("useradd " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -M -N -r") != EXIT_SUCCESS) + { + // throw PiPedalException("Failed to create service account."); + } + system("usermod -a -G jack " SERVICE_ACCOUNT_NAME); + + // create and configure /var directory. + + std::filesystem::path varDirectory("/var/pipedal"); + std::filesystem::create_directory(varDirectory); + + { + std::stringstream s; + s << "chgrp " SERVICE_GROUP_NAME " " << varDirectory; + system(s.str().c_str()); + } + { + std::stringstream s; + s << "chown " SERVICE_ACCOUNT_NAME << " " << varDirectory; + system(s.str().c_str()); + } + + { + std::stringstream s; + s << "chmod 775 " << varDirectory; + system(s.str().c_str()); + } + { + std::stringstream s; + s << "chmod g+s " << varDirectory; // child files/directories inherit ownership. + system(s.str().c_str()); + } + + // authbind port. + + if (authBindRequired) + { + std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort; + + { + // create it. + std::ofstream f(portAuthFile); + } + { + // own it. + std::stringstream s; + s << "chown " SERVICE_ACCOUNT_NAME " " << portAuthFile; + exec(s); + } + { + // group own it. + std::stringstream s; + s << "chgrp " SERVICE_GROUP_NAME " " << portAuthFile; + exec(s); + } + { + std::stringstream s; + s << "chmod 770 " << portAuthFile; + exec(s); + } + } + + cout << "Creating Systemd file." << endl; + + std::map map; + + int shutdownPort = 3147; + map["DESCRIPTION"] = "PiPedal Web Service"; + { + std::stringstream s; + + if (authBindRequired) + { + s << findOnPath("authbind").string() << " --deep "; + } + s + << (programPrefix / "bin/pipedald").string() + << " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd -shutdownPort " << shutdownPort; + + map["COMMAND"] = s.str(); + } + WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/template.service"), GetServiceFileName(NATIVE_SERVICE)); + + map["DESCRIPTION"] = "PiPedal Shutdown Service"; + { + std::stringstream s; + + s + << (programPrefix / "bin/pipedalshutdownd").string() + << " -port " << shutdownPort; + + map["COMMAND"] = s.str(); + } + WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/templateShutdown.service"), GetServiceFileName(SHUTDOWN_SERVICE)); + + + + system("systemctl daemon-reload"); + + cout << "Starting service" << endl; + RestartService(); + EnableService(); + + cout << "Complete" << endl; +} + +int main(int argc, char **argv) +{ + CommandLineParser parser; + bool install = false; + bool uninstall = false; + bool help = false; + bool stop = false, start = false; + bool enable = false, disable = false, restart = false; + std::string prefixOption; + std::string portOption; + + parser.AddOption("-install", &install); + parser.AddOption("-uninstall", &uninstall); + parser.AddOption("-stop", &stop); + parser.AddOption("-start", &start); + parser.AddOption("-enable", &enable); + parser.AddOption("-disable", &disable); + parser.AddOption("-restart", &restart); + parser.AddOption("-h", &help); + parser.AddOption("--help", &help); + parser.AddOption("-prefix", &prefixOption); + parser.AddOption("-port", &portOption); + try + { + parser.Parse(argc, (const char **)argv); + + int actionCount = install + uninstall + stop + start + enable + disable; + if (actionCount > 1) + { + throw PiPedalException("Please provide only one action."); + } + if (actionCount == 0) + { + help = true; + } + } + catch (const std::exception &e) + { + std::string s = e.what(); + cout << "Error: " << s << endl; + exit(EXIT_FAILURE); + } + + if (help || parser.Arguments().size() != 0) + { + cout << "pipedalconfig - Post-install configuration for pipdeal" << endl + << "Copyright (c) 2021 Robin Davies. All rights reserved." << endl + << endl + << "Syntax:" << endl + << " pipedalconfig [Options...]" << endl + << "Options: " << endl + << " -install Install services and service accounts." << endl + << " -uninstall Remove installed services and service accounts." << endl + << " -enable Start the pipedal at boot time." << endl + << " -disable Do not start the pipedal at boot time." << endl + << " -h --help Display this message." << endl + << " -stop Stop the pipedal services." << endl + << " -start Start the pipedal services." << endl + << " -restart Restart the pipedal services." << endl + << " -prefix Either /usr/local or /usr as appropriate for the install" << endl + << " (only valid with the -install option)." << endl + << " -port Port for the web server (only with -install option)." << endl + << " Either a port (e.g. '81'), or a full endpoint (e.g.: " << endl + << " '127.0.0.1:8080'). If no address is specified, the " << endl + << " web server will listen on 0.0.0.0 (any)." << endl + << endl + << "Description:" << endl + << " pipedalconfig performs post-install configuration of pipedal." << endl + << endl; + exit(EXIT_SUCCESS); + } + if (portOption.size() != 0 && !install) + { + cout << "Error: -port option can only be specified with the -install option." << endl; + exit(EXIT_FAILURE); + } + + try + { + std::filesystem::path prefix; + if (prefixOption.length() != 0) + { + prefix = std::filesystem::path(prefixOption); + } + else + { + prefix = std::filesystem::path(argv[0]).parent_path().parent_path(); + + std::filesystem::path pipedalPath = prefix / "bin/pipedald"; + if (!std::filesystem::exists(pipedalPath)) + { + std::stringstream s; + s << "Can't find pipedald executable at " << pipedalPath << ". Try again using the -prefix option."; + throw PiPedalException(s.str()); + } + } + if (install) + { + if (portOption == "") + { + portOption = "80"; + } + if (portOption.find(':') == string::npos) + { + portOption = "0.0.0.0:" + portOption; + } + Install(prefix, portOption); + } + else if (uninstall) + { + } + else if (stop) + { + StopService(); + } + else if (start) + { + StartService(); + } + else if (restart) + { + RestartService(); + } + else if (enable) + { + EnableService(); + } + else if (disable) + { + DisableService(); + } + } + catch (const std::exception &e) + { + cout << "Error: " << e.what() << endl; + exit(EXIT_FAILURE); + } +} \ No newline at end of file diff --git a/src/HtmlHelper.cpp b/src/HtmlHelper.cpp new file mode 100644 index 0000000..e3df294 --- /dev/null +++ b/src/HtmlHelper.cpp @@ -0,0 +1,226 @@ +#include "pch.h" +#include "HtmlHelper.hpp" +#include +#include +#include + +using namespace pipedal; + + +// non-localizable. RFC 7231 Date Format +; +static const char*INVARIANT_WEEK_DAYS[] = + { "Sun","Mon", "Tue", "Wed","Thu", "Fri","Sat"}; +// non-localizable. RFC 7231 Date Format +static const char*INVARIANT_MONTHS[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep","Oct","Nov", "Dec"}; +// non-localizable. RFC 7231 Date Format +static const char*FORMAT = "%s, %02d %s %04d %02d:%02d:%02d GMT"; + +std::string HtmlHelper::timeToHttpDate() +{ + return timeToHttpDate(time(nullptr)); +} + +std::string HtmlHelper::timeToHttpDate(time_t time) +{ + // RFC 7231, IMF-fixdate. + + struct tm gmTm; + + if (gmtime_r(&time,&gmTm) == nullptr) + { + return "Mon, 01 Jan 1970 00:00:00 GMT"; + } + char szBuffer[sizeof("Mon, 01 Jan 1970 00:00:00 GMT+")]; + snprintf(szBuffer,sizeof(szBuffer), FORMAT, + INVARIANT_MONTHS[gmTm.tm_wday], + gmTm.tm_mday, + INVARIANT_MONTHS[gmTm.tm_mon], + gmTm.tm_year, + gmTm.tm_hour, + gmTm.tm_min, + gmTm.tm_sec); + return szBuffer; + +} + + +static int hexN(char c) +{ + if (c >= '0' && c <= '9') return c-'0'; + if (c >= 'a' && c <= 'f') return 10+c-'a'; + if (c >= 'A' && c <= 'F') return 10+c-'A'; + throw std::invalid_argument("Malformed URL."); +} +static char hexChar(char c1, char c2) +{ + return (char)((hexN(c1) << 4) + hexN(c2)); +} + +class SafeCharacterMap { + bool safeCharacter[256]; +public: + SafeCharacterMap() + { + for (int i = 0; i < 0x20; ++i) { + safeCharacter[i] = false; + } + for (int i = 0x20; i < 0x80; ++i) { + safeCharacter[i] = true; + } + for (int i = 0x80; i < 256; ++i) + { + safeCharacter[i] = false; + } + const char *unsafeCharacters = ":/+?=#%@ "; + for (const char*p = unsafeCharacters; *p != 0; ++p) + { + safeCharacter[(uint8_t)*p] = false; + } + } + + + bool isSafeCharacter(char c) { return safeCharacter[(uint8_t)c];} +} g_safeCharacterMap; + + +std::string HtmlHelper::encode_url_segment(const char*pStart, const char*pEnd, bool isQuerySegment ) +{ + std::stringstream s; + encode_url_segment(s,pStart,pEnd,isQuerySegment); + return s.str(); +} + +static char hexChars[] = "0123456789ABCDEF"; + +void HtmlHelper::encode_url_segment(std::ostream&os, const char*pStart, const char *pEnd, bool isQuerySegment) +{ + while (pStart != pEnd) + { + char c = *pStart++; + if (g_safeCharacterMap.isSafeCharacter(c)) + { + os << c; + } else if (c == ' ' && isQuerySegment) + { + os << '+'; + + os << c; + } else { + os << '%' << hexChars[(c >> 4) & 0x0f] << hexChars[c & 0x0F]; + } + } +} + + + + +std::string HtmlHelper::decode_url_segment(const char*pStart, const char*pEnd, bool isQuery) +{ + std::stringstream s; + auto p = pStart; + while (p != pEnd) + { + char c = *p; + ++p; + if (c == '+') + { + s << ' '; + } else if (c != '%') + { + s << c; + } else { + if (pStart+2 < pEnd) + { + char c1 = *p; ++p; + char c2 = *p; ++p; + s << hexChar(c1,c2); + } else { + throw std::invalid_argument("Malformed URL."); + } + } + } + return s.str(); +} + +std::string HtmlHelper::decode_url_segment(const char*text, bool isQuery) +{ + return decode_url_segment(text, text + strlen(text),isQuery); +} + +void HtmlHelper::utf32_to_utf8_stream(std::ostream &s, uint32_t uc) +{ + if (uc < 0x80u) + { + s << (char)uc; + } else if (uc < 0x800u) { + s << (char)(0xC0 + (uc >> 6)); + s << (char)(0x80 + (uc & 0x3F)); + + } else if (uc < 0x10000u) { + s << (char)(0xE0 + (uc >> 12)); + s << (char)(0x80 + ((uc >> 6) & 0x3F)); + s << (char)(0x80 + (uc & 0x3F)); + } else if (uc < 0x0110000) { + s << (char)(0xF0 + (uc >> 18)); + s << (char)(0x80 + ((uc >> 12) & 0x3F)); + s << (char)(0x80 + ((uc >> 6) & 0x3F)); + s << (char)(0x80 + (uc & 0x3F)); + } else { + throw std::range_error("Illegal UTF-32 character."); + } +} + +const std::string ESPECIALS = "()<>@,;:\"/[]?.="; + +#define MAX_FILENAME_LENGTH 96 +#define MAX_SEGMENT_LENGTH 74 // 75 per RFC2047.2. But leave space for a ';' to allow easier breaking of lines. + +std::string HtmlHelper::Rfc5987EncodeFileName(const std::string&name) +{ + // Encode all characters. Let the browser handle safe-ifying the actual name, since that's os dependent. + std::stringstream s; + std::string prefix = "UTF-8''"; + std::string postfix = ""; + s << prefix; + for (char c: name) + { + uint8_t uc = (uint8_t)c; + if (uc < 0x20 || uc >= 0x80 || ESPECIALS.find(c) != std::string::npos) + { + s << '%' << hexChars[uc >> 4] << hexChars[uc & 0x0F]; + } else { + s << c; + } + } + s << postfix; + return s.str(); +} + + +#define MAX_FILE_NAME_LENGHT 96 + +const std::string SF_SPECIALS = " <>@;:\"\'/[]?="; + +std::string HtmlHelper::SafeFileName(const std::string name) +{ + std::stringstream s; + for (char c : name) + { + uint8_t uc = (uint8_t)c; + if (uc < 0x20 || uc >= 0x80 || SF_SPECIALS.find(c) != std::string::npos) + { + s << '_'; + } + else + { + s << c; + } + } + return s.str(); +} + + + + + diff --git a/src/HtmlHelper.hpp b/src/HtmlHelper.hpp new file mode 100644 index 0000000..e0035a6 --- /dev/null +++ b/src/HtmlHelper.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include + +namespace pipedal { + +class HtmlHelper { + +public: + static std::string timeToHttpDate(); + static std::string timeToHttpDate(time_t time); + + + static std::string encode_url_segment(const char*pStart, const char*pEnd, bool isQuerySegment = false); + static void encode_url_segment(std::ostream&os, const char*pStart, const char *pEnd, bool isQuerySegment = false); + static void encode_url_segment(std::ostream&os, const std::string&segment, bool isQuerySegment = false) + { + const char*p = segment.c_str(); + encode_url_segment(os,p, p + segment.length(),isQuerySegment); + } + + + static std::string decode_url_segment(const char*pStart, const char*pEnd, bool isQuerySegment = false); + + static std::string decode_url_segment(const char*text, bool isQuerySegment = false); + + static void utf32_to_utf8_stream(std::ostream &s, uint32_t uc); + + static std::string Rfc5987EncodeFileName(const std::string&name); + + static std::string SafeFileName(const std::string name); + +}; + +} // namespace. \ No newline at end of file diff --git a/src/IEffect.hpp b/src/IEffect.hpp new file mode 100644 index 0000000..13d9361 --- /dev/null +++ b/src/IEffect.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include + +namespace pipedal { + class RealtimeParameterRequest; + + class IEffect { + public: + virtual ~IEffect() {} + virtual long GetInstanceId() const = 0; + virtual int GetControlIndex(const std::string&symbol) const = 0; + virtual void SetControl(int index, float value) = 0; + virtual float GetControlValue(int index) const = 0; + virtual void SetBypass(bool enable) = 0; + virtual float GetOutputControlValue(int controlIndex) const = 0; + + + virtual int GetNumberOfInputAudioPorts() const = 0; + virtual int GetNumberOfOutputAudioPorts() const = 0; + virtual float *GetAudioInputBuffer(int index) const = 0; + virtual float *GetAudioOutputBuffer(int index) const = 0; + virtual void ResetAtomBuffers() = 0; + virtual void RequestParameter(LV2_URID uridUri) = 0; + virtual void GatherParameter(RealtimeParameterRequest*pRequest) = 0; + + virtual std::string AtomToJson(uint8_t*pAtom) = 0; + + + virtual void SetAudioOutputBuffer(int index, float*buffer) = 0; + + virtual void Activate() = 0; + virtual void Deactivate() = 0; + }; +} //namespace \ No newline at end of file diff --git a/src/IpSubnet.hpp b/src/IpSubnet.hpp new file mode 100644 index 0000000..2464788 --- /dev/null +++ b/src/IpSubnet.hpp @@ -0,0 +1,44 @@ +#pragma once +#include "PiPedalException.hpp" + +namespace pipedal { + + class IpSubnet + { + bool isValid = false; + uint32_t ipAddress = 0; + uint32_t mask = 0; + IpSubnet() + { + + } + public: + IPSubnet() { + isValid = false; + } + static IpSubment Parse(std::string&text) + { + int pos = text.find('/'); + if (pos == std::string::npos) + { + throw PiPedalArgumentException("Not a valid netmask."); + } + std::string ipText = text.substr(0,npos); + std::string netmaskText = text.substr(npos+1); + + uint32_t bitMask; + try { + unsigned long t = std::stoul(netmaskText); + if (t > 32 || t == 0) { + throw PiPedalStateException("Invalid netmask."); + } + bitMask ((uint32_t)0xFFFF) << (int)t; + } catch (const std::exception &e) + { + throw PiPedalArgumentException("Invalid netmask."); + } + + + } + }; +} \ No newline at end of file diff --git a/src/JackConfiguration.cpp b/src/JackConfiguration.cpp new file mode 100644 index 0000000..ccdb135 --- /dev/null +++ b/src/JackConfiguration.cpp @@ -0,0 +1,227 @@ +#include "pch.h" +#include "JackConfiguration.hpp" +#include "Lv2Log.hpp" +#include "PiPedalException.hpp" + +#include +#include +#include +#include +#include "defer.hpp" +#include + +using namespace pipedal; + +std::string JackStatusToString(jack_status_t status) +{ + switch (status) + { + default: + return "Unknown Jack Audio error."; + case JackStatus::JackFailure: + return "Jack Audio operation failed."; + case JackStatus::JackInvalidOption: + return "Invalid Jack Audio operation."; + case JackStatus::JackNameNotUnique: + return "Jack Audio name in use."; + case JackStatus::JackServerStarted: + return "Jack Audio Server started."; + case JackStatus::JackServerFailed: + return "Jack Audio Server failed."; + case JackStatus::JackServerError: + return "Can't connect to the Jack Audio Server."; + case JackStatus::JackNoSuchClient: + return "Jack Audio client not found."; + case JackLoadFailure: + return "Jack Audio client failed to load."; + case JackStatus::JackInitFailure: + return "Failed to initialize the Jack Audio client."; + case JackStatus::JackShmFailure: + return "Jack Audio failed to access shared memory."; + case JackStatus::JackVersionError: + return "Jack Audio Server version error."; + case JackStatus::JackClientZombie: + return "JackClientZombie error."; + } +}; + +JackConfiguration::JackConfiguration() +{ + this->errorStatus_ = "Not initialized."; +} + +JackConfiguration::~JackConfiguration() +{ +} + +static void AddPorts(jack_client_t *client, std::vector *output, const char *port_name_pattern, + const char *type_name_pattern, + unsigned long flags) +{ + const char**ports = jack_get_ports(client, port_name_pattern, type_name_pattern, flags); + if (ports != nullptr) + { + for (const char **p = ports; *p != nullptr; ++p) + { + const char *portName = *p; + output->push_back(portName); + } + jack_free(ports); + + } +} + +namespace pipedal { + std::string GetJackErrorMessage(jack_status_t status) + { + std::stringstream s; + s << "Unable connect to Jack audio sever. "; + if (status & JackVersionError) { + s << "Jack server/client version mismatch."; + } else if (status & JackServerError) + { + s << "Server error."; + } else if (status & JackServerFailed) + { + s << "Unable to connect to server."; + } else if (status & JackShmFailure) + { + s << "Unable to access shared memory."; + } else if (status & JackInvalidOption) + { + s << "Invalid option."; + } else if (status & JackInitFailure) + { + s << "Initialization error."; + } else if (status & JackLoadFailure) + { + s << "Can't load client."; + } else if (status ) + { + s << "Unknown error."; + } + return s.str(); + + } +} +void JackConfiguration::Initialize() +{ + jack_status_t status; + + jack_client_t *client = nullptr; + try + { + + client = jack_client_open("PiPedal", JackNullOption, &status); + + if (client == nullptr) + { + std::string error = GetJackErrorMessage(status); + Lv2Log::error(error); + throw PiPedalStateException(error.c_str()); + } + //jack_set_process_callback(client, process_fn, this); + + //jack_on_shutdown(client, jack_shutdown_fn, this); + + //jack_set_session_callback(client, session_callback_fn, NULL); + + this->sampleRate_ = jack_get_sample_rate(client); + blockLength_ = jack_get_buffer_size(client); + midiBufferSize_ = jack_port_type_get_buffer_size(client, JACK_DEFAULT_MIDI_TYPE); + maxAllowedMidiDelta_ = (uint32_t)(jack_nframes_t)(sampleRate_ * 0.2); // max 200ms of allowed delta + + // if (jack_activate(client)) + // { + // this->errorStatus_ = "Failed to activate Jack Audio client."; + // Lv2Log::Error("jack_activate failed."); + // throw PiPedalStateException("jack_activate failed."); + // } + + // enumerate the output ports. + + AddPorts(client, &this->inputAudioPorts_, "system", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput); + AddPorts(client, &this->outputAudioPorts_, "system", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput); + AddPorts(client, &this->inputMidiPorts_, "system", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput); + AddPorts(client, &this->outputMidiPorts_, "system", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput); + isValid_ = true; + this->errorStatus_ = ""; + jack_client_close(client); + } + catch (PiPedalException &e) + { + jack_client_close(client); + this->errorStatus_ = e.what(); + } +} + +JackChannelSelection JackChannelSelection::MakeDefault(const JackConfiguration&config){ + JackChannelSelection result; + for (size_t i = 0; i < std::max((size_t)2,config.GetInputAudioPorts().size()); ++i) + { + result.inputAudioPorts_.push_back(config.GetInputAudioPorts()[i]); + + } + for (size_t i = 0; i < std::max((size_t)2,config.GetOutputAudioPorts().size()); ++i) + { + result.outputAudioPorts_.push_back(config.GetOutputAudioPorts()[i]); + } + return result; + +} + +static std::vector makeValid(const std::vector & selected, const std::vector &available) +{ + std::vector result; + for (size_t i = 0; i < selected.size(); ++i) + { + std::string t = selected[i]; + bool found = false; + + for (size_t j = 0; j < available.size(); ++j) + { + if (t == available[j]) + { + found = true; + break; + } + } + if (found) { + result.push_back(t); + } + } + return result; +} +JackChannelSelection JackChannelSelection::RemoveInvalidChannels(const JackConfiguration&config) const +{ + JackChannelSelection result; + result.inputAudioPorts_ = makeValid(this->inputAudioPorts_,config.GetInputAudioPorts()); + result.outputAudioPorts_ = makeValid(this->outputAudioPorts_,config.GetOutputAudioPorts()); + result.inputMidiPorts_ = makeValid(this->inputMidiPorts_, config.GetInputMidiPorts()); + if (!result.isValid()) + { + return this->MakeDefault(config); + } + return result; +} +JSON_MAP_BEGIN(JackChannelSelection) + JSON_MAP_REFERENCE(JackChannelSelection,inputAudioPorts) + JSON_MAP_REFERENCE(JackChannelSelection,outputAudioPorts) + JSON_MAP_REFERENCE(JackChannelSelection,inputMidiPorts) + +JSON_MAP_END() + +JSON_MAP_BEGIN(JackConfiguration) + JSON_MAP_REFERENCE(JackConfiguration,isValid) + JSON_MAP_REFERENCE(JackConfiguration,isRestarting) + JSON_MAP_REFERENCE(JackConfiguration,errorStatus) + JSON_MAP_REFERENCE(JackConfiguration,sampleRate) + JSON_MAP_REFERENCE(JackConfiguration,blockLength) + JSON_MAP_REFERENCE(JackConfiguration,midiBufferSize) + JSON_MAP_REFERENCE(JackConfiguration,maxAllowedMidiDelta) + JSON_MAP_REFERENCE(JackConfiguration,inputAudioPorts) + JSON_MAP_REFERENCE(JackConfiguration,outputAudioPorts) + JSON_MAP_REFERENCE(JackConfiguration,inputMidiPorts) + JSON_MAP_REFERENCE(JackConfiguration,outputMidiPorts) +JSON_MAP_END() + diff --git a/src/JackConfiguration.hpp b/src/JackConfiguration.hpp new file mode 100644 index 0000000..9c2ce10 --- /dev/null +++ b/src/JackConfiguration.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include "json.hpp" + +namespace pipedal +{ + + + class JackConfiguration + { + private: + bool isValid_ = false; + std::string errorStatus_; + + bool isRestarting_ = false; + + uint32_t sampleRate_ = 48000; + size_t blockLength_ = 1024; + size_t midiBufferSize_ = 16*1024; + uint32_t maxAllowedMidiDelta_ = 0; + + std::vector inputAudioPorts_; + std::vector outputAudioPorts_; + std::vector inputMidiPorts_; + std::vector outputMidiPorts_; + public: + JackConfiguration(); + void Initialize(); + ~JackConfiguration(); + bool isValid() const { return isValid_;} + bool isRestarting() const { return isRestarting_; } + void SetIsRestarting(bool value) { isRestarting_ = value; } + uint32_t GetSampleRate() const { return sampleRate_; } + size_t GetBlockLength() const { return blockLength_; } + size_t GetMidiBufferSize() const { return midiBufferSize_;} + double GetMaxAllowedMidiDelta() const { return maxAllowedMidiDelta_; } + + const std::vector &GetInputAudioPorts() const { return inputAudioPorts_; } + const std::vector &GetOutputAudioPorts() const { return outputAudioPorts_; } + const std::vector &GetInputMidiPorts() const { return inputMidiPorts_; } + const std::vector &GetOutputMidiPorts() const { return outputMidiPorts_; } + + DECLARE_JSON_MAP(JackConfiguration); + + }; + class JackChannelSelection { + private: + std::vector inputAudioPorts_; + std::vector outputAudioPorts_; + std::vector inputMidiPorts_; + public: + JackChannelSelection() + { + } + + bool isValid() const { + return inputAudioPorts_.size() != 0 && outputAudioPorts_.size() != 0; + } + + const std::vector& GetInputAudioPorts() const + { + return inputAudioPorts_; + } + const std::vector& getOutputAudioPorts() const + { + return outputAudioPorts_; + } + + const std::vector& GetInputMidiPorts() const + { + return inputMidiPorts_; + } + JackChannelSelection RemoveInvalidChannels(const JackConfiguration&config) const; + + static JackChannelSelection MakeDefault(const JackConfiguration&config); + + DECLARE_JSON_MAP(JackChannelSelection); + }; + + +} // namespace. \ No newline at end of file diff --git a/src/JackHost.cpp b/src/JackHost.cpp new file mode 100644 index 0000000..5c95e5a --- /dev/null +++ b/src/JackHost.cpp @@ -0,0 +1,1376 @@ +#include "JackHost.hpp" + +#include "Lv2Log.hpp" + +using namespace pipedal; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "VuUpdate.hpp" + +#include "RingBuffer.hpp" +#include "RingBufferReader.hpp" + +#include "PiPedalException.hpp" +#include "pthread.h" +#include "sched.h" +#include +#include +#include +#include "Lv2EventBufferWriter.hpp" + +#ifdef __linux__ +#include +#include +#include +#endif + +#include "ShutdownClient.hpp" + +const double VU_UPDATE_RATE_S = 1.0 / 30; +const double OVERRUN_GRACE_PERIOD_S = 15; +using namespace pipedal; + +const int MIDI_LV2_BUFFER_SIZE = 16 * 1024; + +namespace pipedal +{ + // private import from JackConfiguration.cpp + std::string GetJackErrorMessage(jack_status_t status); +} + +class JackHostImpl : public JackHost +{ +private: + std::recursive_mutex mutex; + int64_t overrunGracePeriodSamples = 0; + + IJackHostCallbacks *pNotifyCallbacks = nullptr; + + virtual void SetNotificationCallbacks(IJackHostCallbacks *pNotifyCallbacks) + { + this->pNotifyCallbacks = pNotifyCallbacks; + } + + const size_t RING_BUFFER_SIZE = 64 * 1024; + + RingBuffer inputRingBuffer; + RingBuffer outputRingBuffer; + + RingBufferReader realtimeReader; + RingBufferWriter realtimeWriter; + RingBufferReader hostReader; + RingBufferWriter hostWriter; + + JackChannelSelection channelSelection; + bool active = false; + jack_client_t *client = nullptr; + + std::shared_ptr currentPedalBoard; + std::vector> activePedalBoards; // pedalboards that have been sent to the audio queue. + Lv2PedalBoard *realtimeActivePedalBoard = nullptr; + + std::vector inputPorts; + std::vector outputPorts; + std::vector midiInputPorts; + + std::vector midiLv2Buffers; + + uint32_t sampleRate; + uint64_t currentSample = 0; + + std::atomic underruns = 0; + std::atomic lastUnderrunTime = + std::chrono::system_clock::from_time_t(0); + + int XrunCallback() + { + ++this->underruns; + this->lastUnderrunTime = std::chrono::system_clock ::now(); + return 0; + } + + static int xrun_callback_fn(void *arg) + { + return ((JackHostImpl *)arg)->XrunCallback(); + } + + virtual void Close() + { + std::lock_guard guard(mutex); + if (!isOpen) + return; + + isOpen = false; + StopReaderThread(); + if (active) + { + // disconnect ports. + for (size_t i = 0; i < this->inputPorts.size(); ++i) + { + auto port = inputPorts[i]; + if (port != nullptr) + { + jack_disconnect(client, channelSelection.GetInputAudioPorts()[i].c_str(), jack_port_name(port)); + } + } + for (size_t i = 0; i < outputPorts.size(); ++i) + { + auto port = outputPorts[i]; + if (port != nullptr) + { + jack_disconnect(client, channelSelection.getOutputAudioPorts()[i].c_str(), jack_port_name(port)); + } + } + for (size_t i = 0; i < midiInputPorts.size(); ++i) + { + auto port = midiInputPorts[i]; + if (port != nullptr) + { + jack_disconnect(client, channelSelection.GetInputMidiPorts()[i].c_str(), jack_port_name(port)); + } + } + + jack_deactivate(client); + + jack_set_process_callback(client, nullptr, nullptr); + jack_on_shutdown(client, nullptr, nullptr); + jack_set_session_callback(client, nullptr, NULL); + jack_set_xrun_callback(client, nullptr, nullptr); + + active = false; + } + // unregister ports. + for (size_t i = 0; i < this->inputPorts.size(); ++i) + { + auto port = inputPorts[i]; + if (port) + { + jack_port_unregister(client, port); + } + } + inputPorts.clear(); + + for (size_t i = 0; i < this->outputPorts.size(); ++i) + { + auto port = outputPorts[i]; + if (port) + { + jack_port_unregister(client, port); + } + } + outputPorts.clear(); + for (size_t i = 0; i < this->midiInputPorts.size(); ++i) + { + auto port = midiInputPorts[i]; + if (port) + { + jack_port_unregister(client, port); + } + } + midiInputPorts.resize(0); + + for (size_t i = 0; i < midiLv2Buffers.size(); ++i) + { + delete[] midiLv2Buffers[i]; + } + midiLv2Buffers.resize(0); + + if (client) + { + jack_client_close(client); + client = nullptr; + } + // release any pdealboards owned by the process thread. + this->activePedalBoards.resize(0); + this->realtimeActivePedalBoard = nullptr; + + // clean up any realtime buffers that may have been lost in transit. + // TODO: These should be lists, really. There may be multiple items in flight.. + if (realtimeVuBuffers != nullptr) + { + delete realtimeVuBuffers; + realtimeVuBuffers = nullptr; + } + if (realtimeMonitorPortSubscriptions != nullptr) + { + delete realtimeMonitorPortSubscriptions; + realtimeVuBuffers = nullptr; + } + } + + void ZeroBuffer(float *buffer, jack_nframes_t nframes) + { + for (jack_nframes_t i = 0; i < nframes; ++i) + { + buffer[i] = 0; + } + } + void ZeroOutputBuffers(jack_nframes_t nframes) + { + for (int i = 0; i < this->outputPorts.size(); ++i) + { + float *out = (float *)jack_port_get_buffer(this->outputPorts[i], nframes); + if (out) + { + ZeroBuffer(out, nframes); + } + } + } + RealtimeVuBuffers *realtimeVuBuffers = nullptr; + size_t vuSamplesPerUpdate = 0; + int64_t vuSamplesRemaining = 0; + + void freeRealtimeVuConfiguration() + { + if (this->realtimeVuBuffers != nullptr) + { + realtimeWriter.FreeVuSubscriptions(this->realtimeVuBuffers); + + this->realtimeVuBuffers = nullptr; + } + } + + RealtimeMonitorPortSubscriptions *realtimeMonitorPortSubscriptions = nullptr; + + void freeRealtimeMonitorPortSubscriptions() + { + if (this->realtimeMonitorPortSubscriptions != nullptr) + { + realtimeWriter.FreeMonitorPortSubscriptions(this->realtimeMonitorPortSubscriptions); + + this->realtimeMonitorPortSubscriptions = nullptr; + } + } + + void writeVu() + { + // throttling: we send one; but won't send another until the host thread + // acknowledges receipt. + + if (!realtimeVuBuffers->waitingForAcknowledge) + { + auto pResult = realtimeVuBuffers->GetResult(currentSample); + + this->realtimeWriter.SendVuUpdate(pResult); + realtimeVuBuffers->waitingForAcknowledge = true; + } + } + + void processMonitorPortSubscriptions(uint32_t nframes) + { + for (size_t i = 0; i < this->realtimeMonitorPortSubscriptions->subscriptions.size(); ++i) + { + auto &portSubscription = realtimeMonitorPortSubscriptions->subscriptions[i]; + + portSubscription.samplesToNextCallback -= portSubscription.sampleRate; + if (portSubscription.samplesToNextCallback < 0) + { + portSubscription.samplesToNextCallback += portSubscription.sampleRate; + if (!portSubscription.waitingForAck) + { + portSubscription.waitingForAck = true; + float value = realtimeActivePedalBoard->GetControlOutputValue( + portSubscription.instanceIndex, + portSubscription.portIndex); + + this->realtimeWriter.SendMonitorPortUpdate( + portSubscription.callbackPtr, + portSubscription.subscriptionHandle, + value); + } + } + } + } + + RealtimeParameterRequest *pParameterRequests = nullptr; + + bool reEntered = false; + void ProcessInputCommands() + { + if (reEntered) + { + throw PiPedalStateException("Rentry of process command."); + } + reEntered = true; + + while (true) + { + RingBufferCommand command; + size_t space = realtimeReader.readSpace(); + if (space <= sizeof(RingBufferCommand)) // RingBufferCommand + at least 1 more byte for the body. + break; + if (!realtimeReader.read(&command)) + { + break; + } + switch (command) + { + case RingBufferCommand::SetValue: + { + SetControlValueBody body; + realtimeReader.readComplete(&body); + this->realtimeActivePedalBoard->SetControlValue(body.effectIndex, body.controlIndex, body.value); + break; + } + case RingBufferCommand::ParameterRequest: + { + RealtimeParameterRequest *pRequest = nullptr; + realtimeReader.readComplete(&pRequest); + + // link to the list of parameter requests. + pRequest->pNext = pParameterRequests; + pParameterRequests = pRequest; + break; + } + case RingBufferCommand::AckVuUpdate: + { + bool dummy; + realtimeReader.readComplete(&dummy); + if (this->realtimeVuBuffers) + { + this->realtimeVuBuffers->waitingForAcknowledge = false; + } + + break; + } + case RingBufferCommand::AckMonitorPortUpdate: + { + int64_t subscriptionHandle = 0; + realtimeReader.readComplete(&subscriptionHandle); + if (this->realtimeMonitorPortSubscriptions != nullptr) + { + for (size_t i = 0; i < this->realtimeMonitorPortSubscriptions->subscriptions.size(); ++i) + { + if (this->realtimeMonitorPortSubscriptions->subscriptions[i].subscriptionHandle == subscriptionHandle) + { + this->realtimeMonitorPortSubscriptions->subscriptions[i].waitingForAck = false; + } + } + } + break; + } + case RingBufferCommand::SetMonitorPortSubscription: + { + RealtimeMonitorPortSubscriptions *pSubscriptions; + realtimeReader.readComplete(&pSubscriptions); + this->freeRealtimeMonitorPortSubscriptions(); + this->realtimeMonitorPortSubscriptions = pSubscriptions; + break; + } + case RingBufferCommand::SetVuSubscriptions: + { + RealtimeVuBuffers *configuration; + realtimeReader.readComplete(&configuration); + this->freeRealtimeVuConfiguration(); + this->realtimeVuBuffers = configuration; + if (this->realtimeVuBuffers != nullptr) + { + this->realtimeVuBuffers->waitingForAcknowledge = false; + } + vuSamplesRemaining = vuSamplesPerUpdate; + + break; + } + case RingBufferCommand::SetBypass: + { + SetBypassBody body; + realtimeReader.readComplete(&body); + this->realtimeActivePedalBoard->SetBypass(body.effectIndex, body.enabled); + break; + } + case RingBufferCommand::ReplaceEffect: + { + ReplaceEffectBody body; + realtimeReader.readComplete(&body); + + auto oldValue = this->realtimeActivePedalBoard; + this->realtimeActivePedalBoard = body.effect; + + realtimeWriter.EffectReplaced(oldValue); + + // invalidate the possibly no-good subscriptions. Model will update them shortly. + freeRealtimeVuConfiguration(); + freeRealtimeMonitorPortSubscriptions(); + break; + } + default: + throw PiPedalStateException("Unknown Ringbuffer command."); + } + } + reEntered = false; + } + + void OnMidiValueChanged(uint64_t instanceId, int controlIndex, float value) + { + realtimeWriter.MidiValueChanged(instanceId, controlIndex, value); + } + static void fnMidiValueChanged(void *data, uint64_t instanceId, int controlIndex, float value) + { + ((JackHostImpl *)data)->OnMidiValueChanged(instanceId, controlIndex, value); + } + void ProcessJackMidi() + { + Lv2EventBufferWriter eventBufferWriter(this->eventBufferUrids); + + for (int i = 0; i < this->midiInputPorts.size(); ++i) + { + jack_port_t *port = midiInputPorts[i]; + void *portBuffer = jack_port_get_buffer(midiInputPorts[i], 0); + if (portBuffer) + { + uint8_t *lv2Buffer = this->midiLv2Buffers[i]; + jack_nframes_t n = jack_midi_get_event_count(portBuffer); + + eventBufferWriter.Reset(lv2Buffer, MIDI_LV2_BUFFER_SIZE); + auto iterator = eventBufferWriter.begin(); + + for (jack_nframes_t frame = 0; frame < n; ++frame) + { + jack_midi_event_t event; + if (jack_midi_event_get(&event, portBuffer, frame) == 0) + { + eventBufferWriter.writeMidiEvent(iterator, 0, event.size, event.buffer); + + this->realtimeActivePedalBoard->OnMidiMessage(event.size, event.buffer, this, fnMidiValueChanged); + if (listenForMidiEvent) + { + if (event.size >= 3) + { + uint8_t cmd = (uint8_t)(event.buffer[0] & 0xF0); + bool isNote = cmd == 0x90; + bool isControl = cmd == 0xB0; + if (isNote || isControl) + { + realtimeWriter.OnMidiListen(isNote, event.buffer[1]); + } + } + } + } + } + } + } + } + +#define RESET_XRUN_SAMPLES 22050ul // 1/2 a second-ish. + + int OnProcess(jack_nframes_t nframes) + { + try + { + jack_default_audio_sample_t *in, *out; + + pParameterRequests = nullptr; + + ProcessInputCommands(); + + bool processed = false; + + Lv2PedalBoard *pedalBoard = this->realtimeActivePedalBoard; + if (pedalBoard != nullptr) + { + ProcessJackMidi(); + float *inputBuffers[4]; + float *outputBuffers[4]; + bool buffersValid = true; + for (int i = 0; i < inputPorts.size(); ++i) + { + float *input = (float *)jack_port_get_buffer(inputPorts[i], nframes); + if (input == nullptr) + { + buffersValid = false; + break; + } + inputBuffers[i] = input; + } + inputBuffers[inputPorts.size()] = nullptr; + + for (int i = 0; i < outputPorts.size(); ++i) + { + float *output = (float *)jack_port_get_buffer(outputPorts[i], nframes); + if (output == nullptr) + { + buffersValid = false; + break; + } + outputBuffers[i] = output; + } + outputBuffers[outputPorts.size()] = nullptr; + + if (buffersValid) + { + pedalBoard->ResetAtomBuffers(); + pedalBoard->ProcessParameterRequests(pParameterRequests); + + processed = pedalBoard->Run(inputBuffers, outputBuffers, (uint32_t)nframes); + if (processed) + { + if (this->realtimeVuBuffers != nullptr) + { + pedalBoard->ComputeVus(this->realtimeVuBuffers, (uint32_t)nframes); + + vuSamplesRemaining -= nframes; + if (vuSamplesRemaining <= 0) + { + writeVu(); + vuSamplesRemaining += vuSamplesPerUpdate; + } + } + if (this->realtimeMonitorPortSubscriptions != nullptr) + { + processMonitorPortSubscriptions(nframes); + } + } + pedalBoard->GatherParameterRequests(pParameterRequests); + } + } + + // in = jack_port_get_buffer(input_port, nframes); + // out = jack_port_get_buffer(output_port, nframes); + // memcpy(out, in, + // sizeof(jack_default_audio_sample_t) * nframes); + if (!processed) + { + ZeroOutputBuffers(nframes); + } + + if (pParameterRequests != nullptr) + { + this->realtimeWriter.ParameterRequestComplete(pParameterRequests); + } + // provide a grace period for undderruns, while spinning up. (15 second-ish) + if (currentSample <= this->overrunGracePeriodSamples && currentSample + nframes > this->overrunGracePeriodSamples) + { + this->underruns = 0; + } + this->currentSample += nframes; + + } + catch (const std::exception &e) + { + Lv2Log::error("Fatal error while processing jack audio. (%s)", e.what()); + throw; + } + + return 0; + } + + static int process_fn(jack_nframes_t nframes, void *arg) + { + return ((JackHostImpl *)arg)->OnProcess(nframes); + } + void OnShutdown() + { + Lv2Log::info("Jack Audio Server has shut down."); + } + + static void + jack_shutdown_fn(void *arg) + { + ((JackHostImpl *)arg)->OnShutdown(); + } + + void OnSessionCallback(jack_session_event_t *event) + { + char retval[100]; + Lv2Log::info("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit"); + + snprintf(retval, 100, "jack_simple_session_client %s", event->client_uuid); + event->command_line = strdup(retval); + + jack_session_reply(client, event); + + if (event->type == JackSessionSaveAndQuit) + { + // simple_quit = 1; + } + + jack_session_event_free(event); + } + + static void jack_error_fn(const char *msg) + { + Lv2Log::error("Jack - %s", msg); + } + static void jack_info_fn(const char *msg) + { + Lv2Log::info("Jack - %s", msg); + } + + static void + session_callback_fn(jack_session_event_t *event, void *arg) + { + ((JackHostImpl *)arg)->OnSessionCallback(event); + }; + + Lv2EventBufferUrids eventBufferUrids; + +public: + JackHostImpl(IHost *pHost) + : inputRingBuffer(RING_BUFFER_SIZE), + outputRingBuffer(RING_BUFFER_SIZE), + realtimeReader(&this->inputRingBuffer), + realtimeWriter(&this->outputRingBuffer), + hostReader(&this->outputRingBuffer), + hostWriter(&this->inputRingBuffer), + eventBufferUrids(pHost) + { + jack_set_error_function(jack_error_fn); + jack_set_info_function(jack_info_fn); + } + virtual ~JackHostImpl() + { + Close(); + CleanRestartThreads(true); + jack_set_error_function(nullptr); + jack_set_info_function(nullptr); + } + + virtual JackConfiguration GetServerConfiguration() + { + JackConfiguration result; + + result.Initialize(); + return result; + } + + virtual uint32_t GetSampleRate() + { + return this->sampleRate; + } + + void OnAudioComplete() + { + // there is actually no compelling circumstance in which this should ever happen. + + Lv2Log::error("Audio processing terminated unexpectedly."); + realtimeWriter.AudioStopped(); + } + bool terminateThread; + void ThreadProc() + { + +#if defined(__WIN32) + // bump thread prioriy two levels to + // ensure that the service thread doesn't + // get bogged down by UIwork. Doesn't have to be realtime, but it + // MUST run at higher priority than UI threads. + xxx; // TO DO. +#elif defined(__linux__) + int min = sched_get_priority_min(SCHED_RR); + int max = sched_get_priority_max(SCHED_RR); + + struct sched_param param; + memset(¶m, 0, sizeof(param)); + param.sched_priority = min; + + int result = sched_setscheduler(0, SCHED_RR, ¶m); + if (result == 0) + { + Lv2Log::debug("Service thread priority successfully boosted."); + } +#else + xxx; // TODO! +#endif + + try + { + + struct timespec ts; + // ever 30 seconds, timeout check for and log any overruns. + int pollRateS = 30; + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) + { + Lv2Log::error("clock_gettime failed!"); + return; + } + ts.tv_sec += pollRateS; + uint64_t lastUnderrunCount = this->underruns; + + while (true) + { + + // wait for an event. + // 0 -> ready. -1: timed out. -2: closing. + + int result = hostReader.wait(ts); + if (result == -2) + { + return; + } + else if (result == -1) + { + // timeout. + ts.tv_sec += pollRateS; + uint64_t underruns = this->underruns; + if (underruns != lastUnderrunCount) + { + Lv2Log::info("Jack - Underrun count: %lu", (unsigned long)underruns); + lastUnderrunCount = underruns; + } + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += pollRateS; + } + else + { + while (true) + { + size_t space = hostReader.readSpace(); + if (space <= sizeof(RingBufferCommand)) + { + break; + } + RingBufferCommand command; + if (hostReader.read(&command)) + { + if (command == RingBufferCommand::OnMidiListen) + { + uint16_t msg; + hostReader.read(&msg); + if (this->pNotifyCallbacks) + { + pNotifyCallbacks->OnNotifyMidiListen((msg & 0xFF00) != 0, (uint8_t)msg); + } + } + else if (command == RingBufferCommand::MidiValueChanged) + { + MidiValueChangedBody body; + hostReader.read(&body); + + if (this->pNotifyCallbacks) + { + this->pNotifyCallbacks->OnNotifyMidiValueChanged(body.instanceId, body.controlIndex, body.value); + } + } + else if (command == RingBufferCommand::ParameterRequestComplete) + { + RealtimeParameterRequest *pRequest = nullptr; + hostReader.read(&pRequest); + + std::shared_ptr currentpedalBoard; + + { + std::lock_guard guard(mutex); + currentPedalBoard = this->currentPedalBoard; + } + + while (pRequest != nullptr) + { + auto pNext = pRequest->pNext; + if (pRequest->errorMessage == nullptr && pRequest->responseLength != 0) + { + IEffect *pEffect = currentPedalBoard->GetEffect(pRequest->instanceId); + if (pEffect == nullptr) + { + pRequest->errorMessage = "Effect no longer available."; + } + else + { + pRequest->jsonResponse = pEffect->AtomToJson(pRequest->response); + } + } + pRequest->onJackRequestComplete(pRequest); + pRequest = pNext; + } + } + else if (command == RingBufferCommand::SendMonitorPortUpdate) + { + MonitorPortUpdate body; + hostReader.read(&body); + + if (this->pNotifyCallbacks != nullptr) + { + this->pNotifyCallbacks->OnNotifyMonitorPort(body); + } + this->hostWriter.AckMonitorPortUpdate(body.subscriptionHandle); // please sir, can I have some more? + } + else if (command == RingBufferCommand::SendVuUpdate) + { + const std::vector *updates = nullptr; + hostReader.read(&updates); + + if (this->pNotifyCallbacks) + { + this->pNotifyCallbacks->OnNotifyVusSubscription(*updates); + } + this->hostWriter.AckVuUpdate(); // please sir, can I have some more? + } + else if (command == RingBufferCommand::FreeVuSubscriptions) + { + RealtimeVuBuffers *config; + hostReader.read(&config); + delete config; + } + else if (command == RingBufferCommand::FreeMonitorPortSubscription) + { + RealtimeMonitorPortSubscriptions *pSubscriptions; + hostReader.read(&pSubscriptions); + delete pSubscriptions; + } + else if (command == RingBufferCommand::EffectReplaced) + { + EffectReplacedBody body; + hostReader.read(&body); + OnActivePedalBoardReleased(body.oldEffect); + } + else if (command == RingBufferCommand::AudioStopped) + { + AudioStoppedBody body; + hostReader.read(&body); + OnAudioComplete(); + return; + } + else + { + throw PiPedalStateException("Unrecognized command received from audio thread."); + } + } + } + } + } + } + catch (const std::exception &e) + { + Lv2Log::error("Realtime response thread terminated abnormally. (%s)", e.what()); + } + } + + std::thread *readerThread = nullptr; + + void StopReaderThread() + { + if (readerThread != nullptr) + { + this->terminateThread = true; + this->outputRingBuffer.close(); + + readerThread->join(); + delete readerThread; + readerThread = nullptr; + } + } + void StartReaderThread() + { + terminateThread = false; + auto f = [this]() + { + this->ThreadProc(); + }; + + this->readerThread = new std::thread(f); + } + + bool isOpen = false; + + virtual bool IsOpen() const + { + return isOpen; + } + + uint8_t *AllocateRealtimeBuffer(size_t size) + { + uint8_t *result = new uint8_t[size]; + // populate pages if required. We should have mlocked-ed alread, so they will stay. + for (size_t i = 0; i < size; i += 1024) + { + result[i] = 0; + } + return result; + } + + virtual void Open(const JackChannelSelection &channelSelection) + { + std::lock_guard guard(mutex); + + this->currentSample = 0; + this->underruns = 0; + + if (isOpen) + { + throw PiPedalStateException("Already open."); + } + isOpen = true; + + this->inputRingBuffer.reset(); + this->outputRingBuffer.reset(); + + this->channelSelection = channelSelection; + + StartReaderThread(); + + jack_status_t status; + try + { + + client = jack_client_open("PiPedal", JackNullOption, &status); + + if (client == nullptr || status & JackFailure) + { + if (client) + { + jack_client_close(client); + } + std::string error = GetJackErrorMessage(status); + Lv2Log::error(error); + throw PiPedalStateException(error.c_str()); + } + + if (status & JackServerStarted) + { + Lv2Log::info("Jack server started."); + } + + jack_set_process_callback(client, process_fn, this); + + jack_on_shutdown(client, jack_shutdown_fn, this); + + jack_set_session_callback(client, session_callback_fn, NULL); + + jack_set_xrun_callback(client, xrun_callback_fn, this); + + this->sampleRate = jack_get_sample_rate(client); + + this->overrunGracePeriodSamples = (uint64_t)(((uint64_t)this->sampleRate)*OVERRUN_GRACE_PERIOD_S); + + + this->vuSamplesPerUpdate = (size_t)(sampleRate * VU_UPDATE_RATE_S); + + auto &selectedInputPorts = channelSelection.GetInputAudioPorts(); + this->inputPorts.clear(); + this->outputPorts.clear(); + this->midiInputPorts.clear(); + + this->inputPorts.resize(selectedInputPorts.size()); + for (int i = 0; i < selectedInputPorts.size(); ++i) + { + std::stringstream name; + name << "input" << (i + 1); + this->inputPorts[i] = + jack_port_register( + client, name.str().c_str(), + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + if (this->inputPorts[i] == nullptr) + { + Lv2Log::error("Can't allocate Jack Audio input ports."); + throw PiPedalStateException("Failed to allocate Jack Audio port."); + } + } + auto &selectedOutputPorts = channelSelection.getOutputAudioPorts(); + this->outputPorts.resize(selectedOutputPorts.size()); + for (int i = 0; i < selectedOutputPorts.size(); ++i) + { + std::stringstream name; + name << "output" << (i + 1); + this->outputPorts[i] = + jack_port_register(client, name.str().c_str(), + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + if (this->outputPorts[i] == nullptr) + { + Lv2Log::error("Can't allocate Jack Audio output port."); + throw PiPedalStateException("Failed to allocate Jack Audio port."); + } + } + auto &selectedMidiPorts = channelSelection.GetInputMidiPorts(); + + midiLv2Buffers.resize(selectedMidiPorts.size()); + for (size_t i = 0; i < selectedMidiPorts.size(); ++i) + { + midiLv2Buffers[i] = AllocateRealtimeBuffer(MIDI_LV2_BUFFER_SIZE); + } + + this->midiInputPorts.resize(selectedMidiPorts.size()); + for (int i = 0; i < selectedMidiPorts.size(); ++i) + { + std::stringstream name; + name << "midiIn" << (i + 1); + this->midiInputPorts[i] = + jack_port_register(client, name.str().c_str(), + JACK_DEFAULT_MIDI_TYPE, + JackPortIsInput, 0); + if (this->midiInputPorts[i] == nullptr) + { + std::stringstream s; + s << "can't register Jack port " << name.str().c_str(); + Lv2Log::error(s.str()); + throw PiPedalStateException(s.str().c_str()); + } + } + + int activateResult = jack_activate(client); + if (activateResult == 0) + { + active = true; + + for (int i = 0; i < selectedInputPorts.size(); ++i) + { + auto result = jack_connect(client, selectedInputPorts[i].c_str(), jack_port_name(this->inputPorts[i])); + if (result) + { + Lv2Log::error("Can't connect input port %s", selectedInputPorts[i].c_str()); + throw PiPedalStateException("Jack Audio port connection failed."); + } + } + for (int i = 0; i < selectedOutputPorts.size(); ++i) + { + auto result = jack_connect(client, jack_port_name(this->outputPorts[i]), selectedOutputPorts[i].c_str()); + if (result) + { + Lv2Log::error("Can't connect output port %s", selectedOutputPorts[i].c_str()); + throw PiPedalStateException("Jack Audio port connection failed."); + } + } + for (int i = 0; i < selectedMidiPorts.size(); ++i) + { + auto result = jack_connect(client, selectedMidiPorts[i].c_str(), jack_port_name(this->midiInputPorts[i])); + if (result) + { + Lv2Log::error("Can't connect midi input port %s", selectedMidiPorts[i].c_str()); + throw PiPedalStateException("Jack Audio midi port connection failed."); + } + } + + Lv2Log::info("Jack configuration complete."); + } + else + { + Lv2Log::error("Failed to activate Jack Audio client. (%d)", (int)activateResult); + throw PiPedalStateException("Failed to activate Jack Audio client."); + } + } + catch (PiPedalException &e) + { + Close(); + throw; + } + } + + void OnActivePedalBoardReleased(Lv2PedalBoard *pPedalBoard) + { + if (pPedalBoard) + { + pPedalBoard->Deactivate(); + std::lock_guard guard(mutex); + + for (auto it = activePedalBoards.begin(); it != activePedalBoards.end(); ++it) + { + if ((*it).get() == pPedalBoard) + { + // erase it, relinquishing shared_ptr ownership, usually deleting the object. + activePedalBoards.erase(it); + return; + } + } + } + } + + virtual void SetPedalBoard(const std::shared_ptr &pedalBoard) + { + std::lock_guard guard(mutex); + + this->currentPedalBoard = pedalBoard; + if (active) + { + pedalBoard->Activate(); + this->activePedalBoards.push_back(pedalBoard); + hostWriter.ReplaceEffect(pedalBoard.get()); + } + } + + virtual void SetBypass(long instanceId, bool enabled) + { + std::lock_guard guard(mutex); + if (active && this->currentPedalBoard) + { + // use indices not instance ids, so we can just do a straight array index on the audio thread. + auto index = currentPedalBoard->GetIndexOfInstanceId(instanceId); + if (index >= 0) + { + hostWriter.SetBypass((uint32_t)index, enabled); + } + } + } + + virtual void SetPluginPreset(long instanceId, const std::vector &values) + { + std::lock_guard guard(mutex); + if (active && this->currentPedalBoard) + { + auto effectIndex = currentPedalBoard->GetIndexOfInstanceId(instanceId); + if (effectIndex != -1) + { + for (size_t i = 0; i < values.size(); ++i) + { + const ControlValue &value = values[i]; + int controlIndex = this->currentPedalBoard->GetControlIndex(instanceId, value.key()); + if (controlIndex != -1 && effectIndex != -1) + { + hostWriter.SetControlValue(effectIndex, controlIndex, value.value()); + } + } + } + } + } + + void SetControlValue(long instanceId, const std::string &symbol, float value) + { + std::lock_guard guard(mutex); + if (active && this->currentPedalBoard) + { + // use indices not instance ids, so we can just do a straight array index on the audio thread. + int controlIndex = this->currentPedalBoard->GetControlIndex(instanceId, symbol); + auto effectIndex = currentPedalBoard->GetIndexOfInstanceId(instanceId); + + if (controlIndex != -1 && effectIndex != -1) + { + hostWriter.SetControlValue(effectIndex, controlIndex, value); + } + } + } + + virtual void SetVuSubscriptions(const std::vector &instanceIds) + { + std::lock_guard guard(mutex); + + if (active && this->currentPedalBoard) + { + + if (instanceIds.size() == 0) + { + this->hostWriter.SetVuSubscriptions(nullptr); + } + else + { + RealtimeVuBuffers *vuConfig = new RealtimeVuBuffers(); + + for (size_t i = 0; i < instanceIds.size(); ++i) + { + int64_t instanceId = instanceIds[i]; + auto effect = this->currentPedalBoard->GetEffect(instanceId); + if (!effect) + { + throw PiPedalStateException("Effect not found."); + } + + int index = this->currentPedalBoard->GetIndexOfInstanceId(instanceIds[i]); + vuConfig->enabledIndexes.push_back(index); + VuUpdate v; + v.instanceId_ = instanceId; + // Display mono VUs if a stereo device is being fed identical L/R inputs. + v.isStereoInput_ = effect->GetNumberOfInputAudioPorts() != 1 && effect->GetAudioInputBuffer(0) != effect->GetAudioInputBuffer(1); + v.isStereoOutput_ = effect->GetNumberOfOutputAudioPorts() != 1; + + vuConfig->vuUpdateWorkingData.push_back(v); + vuConfig->vuUpdateResponseData.push_back(v); + } + + this->hostWriter.SetVuSubscriptions(vuConfig); + } + } + } + + RealtimeMonitorPortSubscription MakeRealtimeSubscription(const MonitorPortSubscription &subscription) + { + RealtimeMonitorPortSubscription result; + result.subscriptionHandle = subscription.subscriptionHandle; + result.instanceIndex = this->currentPedalBoard->GetIndexOfInstanceId(subscription.instanceid); + IEffect *pEffect = this->currentPedalBoard->GetEffect(subscription.instanceid); + result.portIndex = pEffect->GetControlIndex(subscription.key); + result.sampleRate = (int)(this->GetSampleRate() * subscription.updateInterval); + result.samplesToNextCallback = result.sampleRate; + PortMonitorCallback *ptr = new PortMonitorCallback(subscription.onUpdate); + result.callbackPtr = ptr; + return result; + } + virtual void SetMonitorPortSubscriptions(const std::vector &subscriptions) + { + if (!active) + return; + if (this->currentPedalBoard == nullptr) + return; + if (subscriptions.size() == 0) + { + this->hostWriter.SetMonitorPortSubscriptions(nullptr); + } + else + { + RealtimeMonitorPortSubscriptions *pSubscriptions = new RealtimeMonitorPortSubscriptions(); + + for (size_t i = 0; i < subscriptions.size(); ++i) + { + pSubscriptions->subscriptions.push_back( + MakeRealtimeSubscription(subscriptions[i])); + } + this->hostWriter.SetMonitorPortSubscriptions(pSubscriptions); + } + } + +private: + class RestartThread + { + JackHostImpl *this_; + JackServerSettings jackServerSettings; + std::function onComplete; + std::atomic isComplete = false; + std::thread *pThread = nullptr; + + public: + RestartThread( + JackHostImpl *host, + const JackServerSettings &jackServerSettings_, + std::function onComplete_) + : this_(host), + jackServerSettings(jackServerSettings_), + onComplete(onComplete_) + { + } + ~RestartThread() + { + pThread->join(); + delete pThread; + } + bool IsComplete() const { return isComplete; } + + void ThreadProc() + { + this_->restarting = true; + this_->Close(); + ShutdownClient::SetJackServerConfiguration(jackServerSettings); + this_->Open(this_->channelSelection); + this_->restarting = false; + onComplete(true, ""); + isComplete = true; + } + static void ThreadProc_(RestartThread *this_) + { + this_->ThreadProc(); + } + void Run() + { + pThread = new std::thread(ThreadProc_, this); + } + }; + + bool restarting = false; + std::vector restartThreads; + +public: + std::recursive_mutex restart_mutex; + virtual void UpdateServerConfiguration(const JackServerSettings &jackServerSettings, + std::function onComplete) + { + std::lock_guard guard(restart_mutex); + RestartThread *pShutdown = new RestartThread(this, jackServerSettings, onComplete); + restartThreads.push_back(pShutdown); + pShutdown->Run(); + } + void CleanRestartThreads(bool final) + { + std::lock_guard guard(restart_mutex); + for (size_t i = 0; i < restartThreads.size(); ++i) + { + if (final) + { + delete restartThreads[i]; + } + else + { + if (restartThreads[i]->IsComplete()) + { + delete restartThreads[i]; + restartThreads.erase(restartThreads.begin() + i); + --i; + } + } + } + if (final) + { + restartThreads.clear(); + } + } + + virtual void getRealtimeParameter(RealtimeParameterRequest *pParameterRequest) + { + if (!active) + { + pParameterRequest->errorMessage = "Not active."; + pParameterRequest->onJackRequestComplete(pParameterRequest); + return; + } + this->hostWriter.ParameterRequest(pParameterRequest); + } + + static int32_t GetRaspberryPiTemperature() + { + try + { + std::ifstream f("/sys/class/thermal/thermal_zone0/temp"); + int32_t temp; + f >> temp; + return temp; + } + catch (std::exception &) + { + return -1000000; + } + } + + virtual JackHostStatus getJackStatus() + { + CleanRestartThreads(false); + using namespace std::chrono; + using std::chrono::duration_cast; + using std::chrono::milliseconds; + + std::lock_guard guard(mutex); + + JackHostStatus result; + result.underruns_ = this->underruns; + auto dt = duration_cast(std::chrono::system_clock ::now().time_since_epoch()).count() - duration_cast(this->lastUnderrunTime.load().time_since_epoch()).count(); + + result.msSinceLastUnderrun_ = (uint64_t)dt; + + result.temperaturemC_ = GetRaspberryPiTemperature(); + + result.active_ = this->active; + result.restarting_ = this->restarting; + + if (client != nullptr) + { + result.cpuUsage_ = jack_cpu_load(this->client); + } + else + { + result.cpuUsage_ = 0; + } + return result; + } + volatile bool listenForMidiEvent; + + virtual void SetListenForMidiEvent(bool listen) + { + this->listenForMidiEvent = listen; + } +}; + +JackHost *JackHost::CreateInstance(IHost *pHost) +{ + return new JackHostImpl(pHost); +} + +JSON_MAP_BEGIN(JackHostStatus) +JSON_MAP_REFERENCE(JackHostStatus, active) +JSON_MAP_REFERENCE(JackHostStatus, restarting) +JSON_MAP_REFERENCE(JackHostStatus, underruns) +JSON_MAP_REFERENCE(JackHostStatus, cpuUsage) +JSON_MAP_REFERENCE(JackHostStatus, msSinceLastUnderrun) +JSON_MAP_REFERENCE(JackHostStatus, temperaturemC) +JSON_MAP_END() diff --git a/src/JackHost.hpp b/src/JackHost.hpp new file mode 100644 index 0000000..2e0da3c --- /dev/null +++ b/src/JackHost.hpp @@ -0,0 +1,145 @@ +#pragma once + +#include "JackConfiguration.hpp" + +#include "Lv2PedalBoard.hpp" +#include "VuUpdate.hpp" +#include "RingBuffer.hpp" +#include "json.hpp" +#include "JackServerSettings.hpp" +#include + +namespace pipedal { + + + +using PortMonitorCallback = std::function; + + +class MonitorPortUpdate +{ +public: + PortMonitorCallback *callbackPtr; // pointer because function<>'s probably aren't POD. + int64_t subscriptionHandle; + float value; +}; +class RealtimeParameterRequest { +public: + int64_t clientId; + int64_t instanceId; + LV2_URID uridUri; + + std::function onJackRequestComplete; + std::function onSuccess; + std::function onError; + + const char*errorMessage = nullptr; + int responseLength = 0; + uint8_t response[2048]; + std::string jsonResponse; + + RealtimeParameterRequest *pNext = nullptr; + +public: + RealtimeParameterRequest( + std::function onJackRequestComplete_, + int64_t clientId_, + int64_t instanceId_, + LV2_URID uridUri_, + std::function onSuccess_, + std::function onError_) + : onJackRequestComplete(onJackRequestComplete_), + clientId(clientId_), + instanceId(instanceId_), + uridUri(uridUri_), + onSuccess(onSuccess_), + onError(onError_) + { + + } + +}; + + +class MonitorPortSubscription { +public: + int64_t subscriptionHandle; + int64_t instanceid; + std::string key; + float updateInterval; + PortMonitorCallback onUpdate; + +}; + +class IJackHostCallbacks { +public: + virtual void OnNotifyVusSubscription(const std::vector & updates) = 0; + virtual void OnNotifyMonitorPort(const MonitorPortUpdate &update) = 0; + virtual void OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, float value) = 0; + virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl) = 0; + + +}; + + +class JackHostStatus { +public: + bool active_; + bool restarting_; + uint64_t underruns_; + float cpuUsage_ = 0; + uint64_t msSinceLastUnderrun_ = 0; + int32_t temperaturemC_ = -100000; + + DECLARE_JSON_MAP(JackHostStatus); + + +}; + +class IHost; + +class JackHost { + +protected: + JackHost() { } +public: + static JackHost*CreateInstance(IHost *pHost); + virtual ~JackHost() { }; + + virtual void UpdateServerConfiguration(const JackServerSettings & jackServerSettings, + std::function onComplete) = 0; + + virtual void SetNotificationCallbacks(IJackHostCallbacks *pNotifyCallbacks) = 0; + + virtual void SetListenForMidiEvent(bool listen) = 0; + + + virtual void Open(const JackChannelSelection & channelSelection) = 0; + virtual void Close() = 0; + + virtual uint32_t GetSampleRate() = 0; + + virtual JackConfiguration GetServerConfiguration() = 0; + + virtual void SetPedalBoard(const std::shared_ptr &pedalBoard) = 0; + + virtual void SetControlValue(long instanceId,const std::string&symbol, float value) = 0; + virtual void SetPluginPreset(long isntanceId, const std::vector & values) = 0; + virtual void SetBypass(long instanceId, bool enabled) = 0; + + virtual bool IsOpen() const = 0; + + virtual void SetVuSubscriptions(const std::vector &instanceIds) = 0; + virtual void SetMonitorPortSubscriptions(const std::vector &subscriptions) = 0; + + virtual void getRealtimeParameter(RealtimeParameterRequest*pParameterRequest) = 0; + + virtual JackHostStatus getJackStatus() = 0; + + +}; + + + + +} //namespace pipedal. \ No newline at end of file diff --git a/src/JackServerSettings.cpp b/src/JackServerSettings.cpp new file mode 100644 index 0000000..ef71fb4 --- /dev/null +++ b/src/JackServerSettings.cpp @@ -0,0 +1,201 @@ +#include "pch.h" + +#include "Lv2Log.hpp" +#include "JackServerSettings.hpp" +#include +#include "PiPedalException.hpp" + +#define DRC_FILENAME "/etc/jackdrc" + +using namespace std; +using namespace pipedal; + +JackServerSettings::JackServerSettings() +{ +} + +static std::vector SplitArgs(const char *szBuff) +{ + std::vector result; + + while (*szBuff != '\0') + { + while (*szBuff == ' ' || *szBuff == '\t' || *szBuff == '\r' || *szBuff == '\n') + ++szBuff; + if (*szBuff == 0) + break; + + std::stringstream s; + while (*szBuff != ' ' && *szBuff != '\t' && *szBuff != '\0' && *szBuff != '\r' && *szBuff != '\n') + { + s.put(*szBuff++); + } + result.push_back(s.str()); + } + + return result; +} + +static uint64_t GetJackArg(const std::vector &args, const char *shortOption, const char *longOption) +{ + int pos = -1; + for (size_t i = 1; i < args.size(); ++i) + { + if (args[i] == shortOption || args[i] == longOption) + { + pos = i; + break; + } + } + if (pos == -1 || pos == args.size() - 1) + { + throw PiPedalException("Can't read Jack configuration."); + } + try + { + unsigned long value = std::stoul(args[pos + 1]); + return value; + } + catch (const std::exception &) + { + throw PiPedalException("Can't read Jack configuration."); + } +} +static void SetJackArg(std::vector &args, const char *shortOption, const char *longOption,uint64_t value) +{ + int pos = -1; + for (size_t i = 1; i < args.size(); ++i) + { + if (args[i] == shortOption || args[i] == longOption) + { + pos = i; + break; + } + } + if (pos == -1 || pos == args.size() - 1) + { + throw PiPedalException("Can't read Jack configuration."); + } + stringstream s; + s << value; + args[pos+1] = s.str(); + return; +} + + + +void JackServerSettings::ReadJackConfiguration() +{ + this->valid_ = false; + + char firstLine[1024]; + + { + ifstream input(DRC_FILENAME); + + if (!input.is_open()) + { + Lv2Log::error("Can't read " DRC_FILENAME); + return; + } + + while (true) + { + if (input.eof()) + { + Lv2Log::error("Premature end of file in " DRC_FILENAME); + return; + } + input.getline(firstLine, sizeof(firstLine)); + if (firstLine[0] != '#') + break; + } + try { + std::vector < std::string> argv = SplitArgs(firstLine); + this->bufferSize_ = GetJackArg(argv, "-p", "-period"); + this->numberOfBuffers_ = (uint32_t)GetJackArg(argv, "-n", "-nperiods"); + this->sampleRate_ = (uint32_t)GetJackArg(argv, "-r", "-rate"); + valid_ = true; + } catch (std::exception &) + { + Lv2Log::error("Can't parse " DRC_FILENAME); + } + } +} + +void JackServerSettings::Write() +{ + this->valid_ = false; + + std::vector precedingLines; + std::vector < std::string> argv; + + { + char firstLine[1024]; + ifstream input(DRC_FILENAME); + + if (!input.is_open()) + { + Lv2Log::error("Can't read " DRC_FILENAME); + return; + } + + while (true) + { + if (input.eof()) + { + Lv2Log::error("Premature end of file in " DRC_FILENAME); + return; + } + input.getline(firstLine, sizeof(firstLine)); + if (firstLine[0] != '#') + break; + precedingLines.push_back(firstLine); + } + + // set new values for arguments. + argv = SplitArgs(firstLine); + try { + SetJackArg(argv, "-p", "-period", this->bufferSize_); + SetJackArg(argv, "-n", "-nperiods", this->numberOfBuffers_); + SetJackArg(argv, "-r", "-rate",this->sampleRate_); + } catch (std::exception &) + { + Lv2Log::error("Can't parse " DRC_FILENAME); + return; + } + } + // write to the output. + try { + ofstream output(DRC_FILENAME); + if (!output.is_open()) + { + throw PiPedalException("Can't write " DRC_FILENAME); + } + for (auto line: precedingLines) + { + output << line << endl; + } + for (size_t i = 0; i < argv.size(); ++i) + { + if (i != 0) { + output << " "; + } + output << argv[i]; + } + output << endl; + } catch (const std::exception &e) { + stringstream s; + s << "jack - " << e.what(); + Lv2Log::error(s.str()); + } +} + +JSON_MAP_BEGIN(JackServerSettings) + JSON_MAP_REFERENCE(JackServerSettings,valid) + JSON_MAP_REFERENCE(JackServerSettings,rebootRequired) + JSON_MAP_REFERENCE(JackServerSettings,sampleRate) + JSON_MAP_REFERENCE(JackServerSettings,bufferSize) + JSON_MAP_REFERENCE(JackServerSettings,numberOfBuffers) +JSON_MAP_END() + diff --git a/src/JackServerSettings.hpp b/src/JackServerSettings.hpp new file mode 100644 index 0000000..1acb9d2 --- /dev/null +++ b/src/JackServerSettings.hpp @@ -0,0 +1,47 @@ +#pragma once +#include +#include "json.hpp" + +namespace pipedal { + // Jack Daemon configuration. + class JackServerSettings { + bool valid_ = false; + bool rebootRequired_ = false; + uint64_t sampleRate_ = 0; + uint32_t bufferSize_ = 0; + uint32_t numberOfBuffers_ = 0; + + public: + JackServerSettings(); + + uint64_t GetSampleRate() const { return sampleRate_; } + uint32_t GetBufferSize() const { return bufferSize_; } + uint32_t GetNumberOfBuffers() const { return numberOfBuffers_; } + + void ReadJackConfiguration(); + + bool IsValid() const { return valid_; } + + JackServerSettings(uint64_t sampleRate, uint32_t bufferSize, uint32_t numberOfBuffers) + { + this->valid_ = true; + this->rebootRequired_ = true; + this->sampleRate_ = sampleRate; this->bufferSize_ = bufferSize; this->numberOfBuffers_ = numberOfBuffers; + } + void Write(); // requires root perms. + void SetRebootRequired(bool value) + { + rebootRequired_ = value; + } + bool Equals(const JackServerSettings&other) + { + return this->sampleRate_ == other.sampleRate_ + && this->bufferSize_ == other.bufferSize_ + && this->numberOfBuffers_ == other.numberOfBuffers_; + } + + + DECLARE_JSON_MAP(JackServerSettings); + + }; +} // namespace \ No newline at end of file diff --git a/src/Locale.cpp b/src/Locale.cpp new file mode 100644 index 0000000..9fb2b73 --- /dev/null +++ b/src/Locale.cpp @@ -0,0 +1,28 @@ +#include "pch.h" + +#include "Locale.hpp" + +#include + + +// Must be UNICODE. Should reflect system locale. (.e.g en-US.UTF8, de-de.UTF8) + +// This is correct for libstdc++; most probably not correct for Windows or CLANG. :-( +using namespace pipedal; + +static const char*getLocale(const char*localeEnvironmentVariable) +{ + const char*result = getenv(localeEnvironmentVariable); + if (result == nullptr) + { + result = getenv("LC_ALL"); + } + if (result == nullptr) { + result = "en_US.UTF-8"; + } + return result; +} + +static std::locale collationLocale(getLocale("LC_COLLATION")); +const std::collate& Locale::collation = std::use_facet >(collationLocale); + diff --git a/src/Locale.hpp b/src/Locale.hpp new file mode 100644 index 0000000..9d3dbd6 --- /dev/null +++ b/src/Locale.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace pipedal { + + class Locale { + public: + static const std::collate& collation; + }; +} diff --git a/src/LogFeature.cpp b/src/LogFeature.cpp new file mode 100644 index 0000000..c9897d3 --- /dev/null +++ b/src/LogFeature.cpp @@ -0,0 +1,74 @@ +#include "LogFeature.hpp" +#include +#include +#include "Lv2Log.hpp" + + +using namespace pipedal; +using namespace std; + + + +int LogFeature::printfFn(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + + LogFeature* logFeature = (LogFeature*)handle; + return logFeature->vprintf(type, fmt, va); +} + +int LogFeature::vprintfFn(LV2_Log_Handle handle, + LV2_URID type, + const char* fmt, + va_list ap) +{ + LogFeature* logFeature = (LogFeature*)handle; + return logFeature->vprintf(type, fmt, ap); +} + +int LogFeature::vprintf(LV2_URID type,const char*fmt, va_list va) +{ + std::lock_guard guard(logMutex); + + const char* prefix = ""; + char buffer[1024]; + int result = vsnprintf(buffer, sizeof(buffer), fmt, va); + + if (type == uris.ridError) + { + Lv2Log::error(buffer); + } + else if (type == uris.ridWarning) + { + Lv2Log::warning(buffer); + } + else if (type == uris.ridNote) + { + Lv2Log::info(buffer); + } + else if (type == uris.ridTrace) + { + Lv2Log::debug(buffer); + } + else { + Lv2Log::info(buffer); + } + return result; +} + + +LogFeature::LogFeature() +{ + feature.URI = LV2_LOG__log; + feature.data = &log; + log.handle = (void*)this; + log.printf = printfFn; + log.vprintf = vprintfFn; +} +void LogFeature::Prepare(MapFeature*map) +{ + uris.Map(map); + +} + diff --git a/src/LogFeature.hpp b/src/LogFeature.hpp new file mode 100644 index 0000000..e1078a9 --- /dev/null +++ b/src/LogFeature.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "lv2/core/lv2.h" + +#include "lv2/atom/atom.h" +#include "lv2/atom/util.h" +#include "lv2/core/lv2.h" +#include "lv2/log/log.h" +#include "lv2/log/logger.h" +#include "lv2/midi/midi.h" +#include "lv2/urid/urid.h" +#include "lv2/atom/atom.h" +#include "MapFeature.hpp" +#include +#include +#include + + +namespace pipedal { + class LogFeature { + + private: + LV2_URID nextAtom = 0; + LV2_Feature feature; + LV2_Log_Log log; + std::mutex logMutex; + struct Uri { + void Map(MapFeature* map) + { + ridError = map->GetUrid(LV2_LOG__Error); + ridNote = map->GetUrid(LV2_LOG__Note); + ridTrace = map->GetUrid(LV2_LOG__Trace); + ridWarning = map->GetUrid(LV2_LOG__Warning); + } + LV2_URID ridError; + LV2_URID ridWarning; + LV2_URID ridNote; + LV2_URID ridTrace; + }; + + Uri uris; + + public: + LogFeature(); + void Prepare(MapFeature* map); + + public: + const LV2_Feature* GetFeature() + { + return &feature; + } + LV2_URID GetUrid(const char* uri); + private: + static int printfFn(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...); + + static int vprintfFn(LV2_Log_Handle handle, + LV2_URID type, + const char* fmt, + va_list ap); + + int vprintf(LV2_URID type, const char* fmt, va_list va); + + + }; +} \ No newline at end of file diff --git a/src/Lv2Effect.cpp b/src/Lv2Effect.cpp new file mode 100644 index 0000000..7486982 --- /dev/null +++ b/src/Lv2Effect.cpp @@ -0,0 +1,667 @@ +#include "pch.h" +#include "Lv2Effect.hpp" +#include "PiPedalException.hpp" +#include +#include +#include "lv2/atom/atom.h" +#include "lv2/atom/util.h" +#include "lv2/core/lv2.h" +#include "lv2/log/log.h" +#include "lv2/log/logger.h" +#include "lv2/midi/midi.h" +#include "lv2/urid/urid.h" +#include "lv2/log/logger.h" +#include "lv2/uri-map/uri-map.h" +#include "lv2/atom/forge.h" +#include "lv2/worker/worker.h" +#include "lv2/patch/patch.h" +#include "lv2/parameters/parameters.h" +#include "lv2/units/units.h" +#include "lv2/atom/util.h" +#include "JackHost.hpp" + +using namespace pipedal; + +const float BYPASS_TIME_S = 0.1f; + +Lv2Effect::Lv2Effect( + IHost *pHost_, + const std::shared_ptr &info_, + const PedalBoardItem &pedalBoardItem) + : pHost(pHost_), pInstance(nullptr), info(info_), uris(pHost) +{ + auto pWorld = pHost_->getWorld(); + + this->bypassStartingSamples = (uint32_t)(pHost->GetSampleRate() * BYPASS_TIME_S); + + this->bypass = pedalBoardItem.isEnabled(); + + // initialize the atom forge used on the realtime thread. + LV2_URID_Map *map = this->pHost->GetLv2UridMap(); + lv2_atom_forge_init(&inputForgeRt, map); + lv2_atom_forge_init(&outputForgeRt, map); + + const LilvPlugins *plugins = lilv_world_get_all_plugins(pWorld); + + auto uriNode = lilv_new_uri(pWorld, pedalBoardItem.uri().c_str()); + const LilvPlugin *pPlugin = lilv_plugins_get_by_uri(plugins, uriNode); + lilv_node_free(uriNode); + + LV2_Feature *const *features = pHost_->GetLv2Features(); + + for (auto p = features; *p != nullptr; ++p) + { + this->features.push_back(*p); + } + + this->work_schedule_feature = nullptr; + if (info_->hasExtension(LV2_WORKER__interface)) + { + // insane implementation. :-( + LV2_Worker_Schedule *schedule = (LV2_Worker_Schedule *)malloc(sizeof(LV2_Worker_Schedule)); + schedule->handle = this; + schedule->schedule_work = worker_schedule_fn; + + work_schedule_feature = (LV2_Feature *)malloc(sizeof(LV2_Feature)); + work_schedule_feature->URI = LV2_WORKER__schedule; + work_schedule_feature->data = schedule; + + this->features.push_back(work_schedule_feature); + } + this->features.push_back(nullptr); + + LV2_Feature **myFeatures = &this->features[0]; + + LilvInstance *pInstance = lilv_plugin_instantiate(pPlugin, pHost->GetSampleRate(), myFeatures); + this->pInstance = pInstance; + + if (info_->hasExtension(LV2_WORKER__interface)) + { + const LV2_Worker_Interface *worker_interface = + (const LV2_Worker_Interface *)lilv_instance_get_extension_data(pInstance, + LV2_WORKER__interface); + this->worker = std::make_unique(pInstance, worker_interface); + } + + this->instanceId = pedalBoardItem.instanceId(); + + this->controlValues.resize(info->ports().size()); + + // Copy default pedalboard settings. + for (auto i = pedalBoardItem.controlValues().begin(); i != pedalBoardItem.controlValues().end(); ++i) + { + auto &v = (*i); + int index = GetControlIndex(v.key()); + if (index != -1) + { + this->controlValues[index] = v.value(); + } + } + PreparePortIndices(); + ConnectControlPorts(); +} + +void Lv2Effect::ConnectControlPorts() +{ + // shared_ptr is not thread-safe. + // Get naked pointers to use on the realtime thread. + int controlArrayLength = 0; + for (int i = 0; i < info->ports().size(); ++i) + { + if (info->ports()[i]->index() >= controlArrayLength) + { + controlArrayLength = info->ports()[i]->index() + 1; + } + } + this->realtimePortInfo.resize(controlArrayLength); + for (int i = 0; i < info->ports().size(); ++i) + { + const auto &port = info->ports()[i]; + if (port->is_control_port()) + { + int index = port->index(); + realtimePortInfo[index] = port.get(); + lilv_instance_connect_port(pInstance, i, &this->controlValues[index]); + } + } +} +void Lv2Effect::PreparePortIndices() +{ + + for (int i = 0; i < info->ports().size(); ++i) + { + const auto &port = info->ports()[i]; + + int portIndex = port->index(); + if (port->is_audio_port()) + { + if (port->is_input()) + { + this->inputAudioPortIndices.push_back(portIndex); + } + else + { + this->outputAudioPortIndices.push_back(portIndex); + } + } + else if (port->is_atom_port()) + { + if (port->is_input()) + { + if (port->supports_midi()) + { + this->inputMidiPortIndices.push_back(portIndex); + } + this->inputAtomPortIndices.push_back(portIndex); + } + else + { + this->outputAtomPortIndices.push_back(portIndex); + if (port->supports_midi()) + { + this->outputMidiPortIndices.push_back(portIndex); + } + } + } + } + inputAudioBuffers.resize(inputAudioPortIndices.size()); + outputAudioBuffers.resize(outputAudioPortIndices.size()); + inputAtomBuffers.resize(inputAtomPortIndices.size()); + outputAtomBuffers.resize(outputAtomPortIndices.size()); +} + +void Lv2Effect::SetAudioInputBuffer(int index, float *buffer) +{ + if (index >= inputAudioPortIndices.size()) + { + throw PiPedalArgumentException("Buffer index out of range."); + } + this->inputAudioBuffers[index] = buffer; + int pluginIndex = this->inputAudioPortIndices[index]; + lilv_instance_connect_port(this->pInstance, pluginIndex, buffer); +} + +void Lv2Effect::SetAudioInputBuffer(float *left) +{ + if (GetNumberOfInputs() > 1) + { + SetAudioInputBuffer(0, left); + SetAudioInputBuffer(1, left); + } + else + { + SetAudioInputBuffer(0, left); + } +} + +void Lv2Effect::SetAudioInputBuffers(float *left, float *right) +{ + if (GetNumberOfInputs() == 1) + { + SetAudioInputBuffer(0, left); + } + else + { + SetAudioInputBuffer(0, left); + SetAudioInputBuffer(1, right); + } +} + +void Lv2Effect::SetAudioOutputBuffer(int index, float *buffer) +{ + this->outputAudioBuffers[index] = buffer; + int pluginIndex = this->outputAudioPortIndices[index]; + lilv_instance_connect_port(pInstance, pluginIndex, buffer); +} + +int Lv2Effect::GetControlIndex(const std::string &key) const +{ + for (int i = 0; i < info->ports().size(); ++i) + { + auto &port = info->ports()[i]; + if (port->symbol() == key) + return port->index(); + } + return -1; +} + +Lv2Effect::~Lv2Effect() +{ + if (worker) + { + worker = nullptr; // delete the worker first! + } + if (pInstance) + { + lilv_instance_free(pInstance); + pInstance = nullptr; + } + if (work_schedule_feature) + { + free(work_schedule_feature->data); + free(work_schedule_feature); + } +} + +void Lv2Effect::Activate() +{ + this->AssignUnconnectedPorts(); + lilv_instance_activate(pInstance); + this->BypassTo(this->bypass ? 1.0f : 0.0f); +} + +void Lv2Effect::AssignUnconnectedPorts() +{ + for (int i = 0; i < this->GetNumberOfInputAudioPorts(); ++i) + { + if (GetAudioInputBuffer(i) == nullptr) + { + int pluginIndex = this->inputAudioPortIndices[i]; + + float *buffer = bufferPool.AllocateBuffer(pHost->GetMaxAudioBufferSize()); + lilv_instance_connect_port(pInstance, pluginIndex, buffer); + } + } + for (int i = 0; i < this->GetNumberOfOutputAudioPorts(); ++i) + { + if (GetAudioOutputBuffer(i) == nullptr) + { + int pluginIndex = this->outputAudioPortIndices[i]; + + float *buffer = bufferPool.AllocateBuffer(pHost->GetMaxAudioBufferSize()); + lilv_instance_connect_port(pInstance, pluginIndex, buffer); + } + } + for (int i = 0; i < this->GetNumberOfInputAtomPorts(); ++i) + { + if (GetAtomInputBuffer(i) == nullptr) + { + int pluginIndex = this->inputAtomPortIndices[i]; + + uint8_t *buffer = bufferPool.AllocateBuffer(pHost->GetAtomBufferSize()); + lilv_instance_connect_port(pInstance, pluginIndex, buffer); + ResetInputAtomBuffer((char *)buffer); + this->inputAtomBuffers[i] = (char *)buffer; + } + } + for (int i = 0; i < this->GetNumberOfOutputAtomPorts(); ++i) + { + if (GetAtomOutputBuffer(i) == nullptr) + { + int pluginIndex = this->outputAtomPortIndices[i]; + + uint8_t *buffer = bufferPool.AllocateBuffer(pHost->GetAtomBufferSize()); + ResetOutputAtomBuffer((char *)buffer); + lilv_instance_connect_port(pInstance, pluginIndex, buffer); + this->outputAtomBuffers[i] = (char *)buffer; + } + } +} +void Lv2Effect::Deactivate() +{ + lilv_instance_deactivate(pInstance); +} + +static inline void CopyBuffer(float *input, float *output, uint32_t frames) +{ + for (uint32_t i = 0; i < frames; ++i) + { + output[i] = input[i]; + } +} + +void Lv2Effect::Run(uint32_t samples) +{ + // close off the atom input frame. + if (this->inputAtomBuffers.size() != 0) + { + lv2_atom_forge_pop(&this->inputForgeRt, &input_frame); + } + + if (worker) + { + // relay worker response + worker->EmitResponses(); + } + lilv_instance_run(pInstance, samples); + + // do soft bypass. + if (this->bypassSamplesRemaining == 0) + { + if (this->currentBypass == 0) + { + // replace the contents of the output buffer(s) with the input buffer(s). + if (this->outputAudioBuffers.size() == 1) + { + CopyBuffer(this->inputAudioBuffers[0], this->outputAudioBuffers[0], samples); + } + else + { + if (this->inputAudioBuffers.size() == 1) + { + CopyBuffer(this->inputAudioBuffers[0], this->outputAudioBuffers[0], samples); + CopyBuffer(this->inputAudioBuffers[0], this->outputAudioBuffers[1], samples); + } + } + } // else leave the output alone. + } + else + { + double currentBypass = this->currentBypass; + double currentBypassDx = this->currentBypassDx; + int32_t bypassSamplesRemaining = (int)this->bypassSamplesRemaining; + + if (this->outputAudioBuffers.size() == 1) + { + float *input = this->inputAudioBuffers[0]; + float *output = this->outputAudioBuffers[0]; + for (uint32_t i = 0; i < samples; ++i) + { + output[i] = currentBypass * output[i] + (1 - currentBypass) * input[i]; + + if (--bypassSamplesRemaining == 0) + { + currentBypassDx = 0; + currentBypass = this->targetBypass; + } + currentBypass += currentBypassDx; + } + } + else + { + float *inputL; + float *inputR; + if (this->inputAudioBuffers.size() == 1) + { + inputL = inputR = inputAudioBuffers[0]; + } + else + { + inputL = inputAudioBuffers[0]; + inputR = inputAudioBuffers[1]; + } + float *outputL = outputAudioBuffers[0]; + float *outputR = outputAudioBuffers[1]; + for (uint32_t i = 0; i < samples; ++i) + { + outputL[i] = currentBypass * outputL[i] + (1 - currentBypass) * inputL[i]; + outputR[i] = currentBypass * outputR[i] + (1 - currentBypass) * inputR[i]; + if (--bypassSamplesRemaining == 0) + { + currentBypassDx = 0; + currentBypass = this->targetBypass; + } + currentBypass += currentBypassDx; + } + } + if (bypassSamplesRemaining <= 0) + { + this->bypassSamplesRemaining = 0; + this->currentBypass = this->targetBypass; + this->currentBypassDx = 0; + } + else + { + this->currentBypass = currentBypass; + this->currentBypassDx = currentBypassDx; + this->bypassSamplesRemaining = bypassSamplesRemaining; + } + } +} + +LV2_Worker_Status Lv2Effect::worker_schedule_fn(LV2_Worker_Schedule_Handle handle, + uint32_t size, + const void *data) +{ + Lv2Effect *this_ = (Lv2Effect *)handle; + this_->worker->ScheduleWork(size, data); + return LV2_WORKER_SUCCESS; +} + +struct BufferHeader +{ + uint32_t size; + uint32_t type; +}; + +void Lv2Effect::ResetInputAtomBuffer(char *data) +{ + BufferHeader *header = (BufferHeader *)data; + header->size = sizeof(LV2_Atom_Sequence_Body); + header->type = uris.atom_Sequence; +} +void Lv2Effect::ResetOutputAtomBuffer(char *data) +{ + BufferHeader *header = (BufferHeader *)data; + header->size = pHost->GetAtomBufferSize() - 8; + header->type = uris.atom_Chunk; +} + +void Lv2Effect::BypassTo(float targetValue) +{ + this->targetBypass = targetValue; + double dx = targetValue - this->currentBypass; + if (dx != 0) + { + this->bypassSamplesRemaining = (int)(bypassStartingSamples * std::abs(dx)); + if (this->bypassStartingSamples == 0) + { + currentBypassDx = 0; + this->currentBypass = targetBypass; + } + else + { + this->currentBypassDx = dx / this->bypassSamplesRemaining; + } + } +} + +void Lv2Effect::ResetAtomBuffers() +{ + for (size_t i = 0; i < this->inputAtomBuffers.size(); ++i) + { + ResetInputAtomBuffer(this->inputAtomBuffers[i]); + } + for (size_t i = 0; i < this->outputAtomBuffers.size(); ++i) + { + ResetOutputAtomBuffer(this->outputAtomBuffers[i]); + } + if (inputAtomBuffers.size() != 0) + { + const uint32_t notify_capacity = pHost->GetAtomBufferSize(); + lv2_atom_forge_set_buffer( + &(this->inputForgeRt), (uint8_t *)(this->inputAtomBuffers[0]), notify_capacity); + + // Start a sequence in the notify input port. + + lv2_atom_forge_sequence_head(&this->inputForgeRt, &input_frame, uris.unitsFrame); + } +} + +void Lv2Effect::RequestParameter(LV2_URID uridUri) +{ + lv2_atom_forge_frame_time(&inputForgeRt, 0); + + LV2_Atom_Forge_Frame objectFrame; + LV2_Atom_Forge_Ref set = + lv2_atom_forge_object(&inputForgeRt, &objectFrame, 0, uris.patch_Get); + + lv2_atom_forge_key(&inputForgeRt, uris.patch_property); + lv2_atom_forge_urid(&inputForgeRt, uridUri); + lv2_atom_forge_pop(&inputForgeRt, &objectFrame); +} + +void Lv2Effect::GatherParameter(RealtimeParameterRequest *pRequest) +{ + LV2_Atom_Sequence*controlInput = (LV2_Atom_Sequence*)GetAtomOutputBuffer(); + LV2_ATOM_SEQUENCE_FOREACH(controlInput, ev) + { + + // frame_offset = ev->time.frames; // not really interested. + + if (lv2_atom_forge_is_object_type(&this->outputForgeRt, ev->body.type)) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + if (obj->body.otype == uris.patch_Set) + { + // Get the property and value of the set message + const LV2_Atom *property = NULL; + const LV2_Atom *value = NULL; + + lv2_atom_object_get( + obj, + uris.patch_property, &property, + uris.patch_value, &value, + 0); + + if (!property) + { + } + else if (property->type != uris.atom_URID) + { + } + else + { + LV2_URID key = ((const LV2_Atom_URID *)property)->body; + if (key == pRequest->uridUri) + { + if (value->size > sizeof(pRequest->response)) + { + pRequest->errorMessage = "Response is too large."; + } else { + pRequest->responseLength = value->size; + memcpy(pRequest->response,value,value->size); + } + break; + } + } + } + } + } +} + +std::string Lv2Effect::AtomToJson(uint8_t*pData) +{ + std::stringstream s; + json_writer writer(s); + LV2_Atom *pAtom = (LV2_Atom*)pData; + + WriteAtom(writer,pAtom); + return s.str(); +} + +void Lv2Effect::WriteAtom(json_writer &writer, LV2_Atom*pAtom) +{ + if (pAtom->type == uris.atom_Blank) + { + writer.write_raw("null"); + } + else if (pAtom->type == uris.atom_float) + { + writer.write( + ((LV2_Atom_Float*)pAtom)->body + ); + + } else if (pAtom->type == uris.atom_Int) + { + writer.write( + ((LV2_Atom_Int*)pAtom)->body + ); + } else if (pAtom->type == uris.atom_Long) + { + writer.write( + ((LV2_Atom_Long*)pAtom)->body + ); + } else if (pAtom->type == uris.atom_Double) + { + writer.write( + ((LV2_Atom_Double*)pAtom)->body + ); + } else if (pAtom->type == uris.atom_Bool) + { + writer.write( + ((LV2_Atom_Bool*)pAtom)->body + ); + } else if (pAtom->type == uris.atom_String) + { + const char *p = (const char*) (((char*) pAtom) + sizeof(LV2_Atom_String)); + writer.write( + p + ); + } else if (pAtom->type == uris.atom_Vector) + { + LV2_Atom_Vector *pVector = (LV2_Atom_Vector*)pAtom; + writer.start_array(); + { + size_t n = (pAtom->size-sizeof(LV2_Atom_Vector))/pVector->body.child_size; + char *pItems = ((char*)pAtom) + sizeof(LV2_Atom_Vector); + if (pVector->body.child_type == uris.atom_float) + { + float *p = (float*)pItems; + for (size_t i = 0; i < n; ++i) + { + if (i != 0) writer.write_raw(","); + writer.write(*p++); + } + } else if (pVector->body.child_type == uris.atom_Int) + { + int32_t *p = (int32_t*)pItems; + for (size_t i = 0; i < n; ++i) + { + if (i != 0) writer.write_raw(","); + writer.write(*p++); + } + } else if (pVector->body.child_type == uris.atom_Long) + { + int64_t *p = (int64_t*)pItems; + for (size_t i = 0; i < n; ++i) + { + if (i != 0) writer.write_raw(","); + writer.write(*p++); + } + } else if (pVector->body.child_type == uris.atom_Double) + { + double *p = (double*)pItems; + for (size_t i = 0; i < n; ++i) + { + if (i != 0) writer.write_raw(","); + writer.write(*p++); + } + } else if (pVector->body.child_type == uris.atom_Bool) + { + bool *p = (bool*)pItems; + for (size_t i = 0; i < n; ++i) + { + if (i != 0) writer.write_raw(","); + writer.write(*p++); + } + } + } + writer.end_array(); + } else if (pAtom->type == uris.atom_Object) + { + writer.start_object(); + + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)pAtom; + std::string id = pHost->Lv2UriudToString(obj->body.id); + std::string type = pHost->Lv2UriudToString(obj->body.otype); + + writer.write_json_member("id",id.c_str()); + writer.write_json_member("lv2Type",type.c_str()); + + bool firstMember = true; + LV2_ATOM_OBJECT_FOREACH (obj, prop) { + if (!firstMember) { + writer.write_raw(","); + } + firstMember = false; + std::string key = pHost->Lv2UriudToString(prop->key); + writer.write(key); + writer.write_raw(": "); + LV2_Atom *value = &(prop->value); + } + writer.end_object(); + + } + +} diff --git a/src/Lv2Effect.hpp b/src/Lv2Effect.hpp new file mode 100644 index 0000000..b3b6ca0 --- /dev/null +++ b/src/Lv2Effect.hpp @@ -0,0 +1,246 @@ +#pragma once + +#include "Lv2Host.hpp" +#include "PedalBoard.hpp" +#include +#include "BufferPool.hpp" + +#include "IEffect.hpp" +#include "Worker.hpp" +#include "lv2/patch/patch.h" +#include "lv2/log/log.h" +#include "lv2/log/logger.h" +#include "lv2/lv2plug.in/ns/extensions/units/units.h" +namespace pipedal +{ + + class Lv2Effect : public IEffect + { + private: + IHost *pHost = nullptr; + int numberOfInputs = 0; + int numberOfOutputs = 0; + int numberOfMidiInputs = 0; + + std::unique_ptr worker; + LilvInstance *pInstance; + std::shared_ptr info; + std::vector controlValues; + std::vector inputAudioPortIndices; + std::vector outputAudioPortIndices; + + std::vector inputAtomPortIndices; + std::vector outputAtomPortIndices; + + std::vector inputMidiPortIndices; + std::vector outputMidiPortIndices; + + std::vector midiInputIndices; + + std::vector inputAudioBuffers; + std::vector outputAudioBuffers; + + std::vector inputAtomBuffers; + std::vector outputAtomBuffers; + std::vector features; + LV2_Feature *work_schedule_feature = nullptr; + + virtual std::string GetUri() const { return info->uri(); } + + std::vector realtimePortInfo; + void PreparePortIndices(); + void ConnectControlPorts(); + void AssignUnconnectedPorts(); + + LV2_Atom_Forge inputForgeRt; + LV2_Atom_Forge_Frame input_frame; + + LV2_Atom_Forge outputForgeRt; + + void WriteAtom(json_writer &writer, LV2_Atom*pAtom); + + class Uris + { + public: + Uris(IHost *pHost) + { + atom_Blank = pHost->GetLv2Urid(LV2_ATOM__Blank); + atom_Path = pHost->GetLv2Urid(LV2_ATOM__Path); + atom_float = pHost->GetLv2Urid(LV2_ATOM__Float); + atom_Double = pHost->GetLv2Urid(LV2_ATOM__Double); + atom_Int = pHost->GetLv2Urid(LV2_ATOM__Int); + atom_Long = pHost->GetLv2Urid(LV2_ATOM__Long); + atom_Bool = pHost->GetLv2Urid(LV2_ATOM__Bool); + atom_String = pHost->GetLv2Urid(LV2_ATOM__String); + atom_Vector = pHost->GetLv2Urid(LV2_ATOM__Vector); + atom_Object = pHost->GetLv2Urid(LV2_ATOM__Object); + + + atom_Sequence = pHost->GetLv2Urid(LV2_ATOM__Sequence); + atom_Chunk = pHost->GetLv2Urid(LV2_ATOM__Chunk); + atom_URID = pHost->GetLv2Urid(LV2_ATOM__URID); + atom_eventTransfer = pHost->GetLv2Urid(LV2_ATOM__eventTransfer); + patch_Get = pHost->GetLv2Urid(LV2_PATCH__Get); + patch_Set = pHost->GetLv2Urid(LV2_PATCH__Set); + patch_Put = pHost->GetLv2Urid(LV2_PATCH__Put); + patch_body = pHost->GetLv2Urid(LV2_PATCH__body); + patch_subject = pHost->GetLv2Urid(LV2_PATCH__subject); + patch_property = pHost->GetLv2Urid(LV2_PATCH__property); + patch_accept = pHost->GetLv2Urid(LV2_PATCH__accept); + patch_value = pHost->GetLv2Urid(LV2_PATCH__value); + unitsFrame = pHost->GetLv2Urid(LV2_UNITS__frame); + + } + LV2_URID patch_accept; + + LV2_URID unitsFrame; + LV2_URID pluginUri; + LV2_URID atom_Blank; + LV2_URID atom_Bool; + LV2_URID atom_float; + LV2_URID atom_Double; + LV2_URID atom_Int; + LV2_URID atom_Long; + LV2_URID atom_String; + LV2_URID atom_Object; + LV2_URID atom_Vector; + LV2_URID atom_Path; + LV2_URID atom_Sequence; + LV2_URID atom_Chunk; + LV2_URID atom_URID; + LV2_URID atom_eventTransfer; + LV2_URID midi_Event; + LV2_URID patch_Get; + LV2_URID patch_Set; + LV2_URID patch_Put; + LV2_URID patch_body; + LV2_URID patch_subject; + LV2_URID patch_property; + LV2_URID patch_value; + LV2_URID param_uiState; + }; + + Uris uris; + + long instanceId; + BufferPool bufferPool; + + static LV2_Worker_Status worker_schedule_fn(LV2_Worker_Schedule_Handle handle, + uint32_t size, + const void *data); + + void ResetInputAtomBuffer(char*data); + void ResetOutputAtomBuffer(char*data); + + uint32_t bypassStartingSamples = 0; + + bool bypass = true; + double targetBypass = 0; + double currentBypass = 0; + double currentBypassDx = 0; + uint32_t bypassSamplesRemaining = 0; + + void BypassTo(float value); + + virtual void RequestParameter(LV2_URID uridUri); + virtual void GatherParameter(RealtimeParameterRequest*pRequest); + + virtual uint8_t*GetAtomInputBuffer() { + if (this->inputAtomBuffers.size() == 0) return nullptr; + return (uint8_t*)this->inputAtomBuffers[0]; + } + virtual uint8_t*GetAtomOutputBuffer() + { + if (this->outputAtomBuffers.size() == 0) return nullptr; + return (uint8_t*)this->outputAtomBuffers[0]; + + } + virtual std::string AtomToJson(uint8_t*pAtom); + + + + public: + Lv2Effect( + IHost *pHost, + const std::shared_ptr &info, + const PedalBoardItem &pedalBoardItem); + ~Lv2Effect(); + + + virtual void ResetAtomBuffers(); + virtual long GetInstanceId() const { return instanceId; } + virtual int GetNumberOfInputAudioPorts() const { return inputAudioPortIndices.size(); } + virtual int GetNumberOfOutputAudioPorts() const { return outputAudioPortIndices.size(); } + int GetNumberOfInputAtomPorts() const { return inputAtomPortIndices.size(); } + int GetNumberOfOutputAtomPorts() const { return outputAtomPortIndices.size(); } + int GetNumberOfMidiInputPorts() const { return inputMidiPortIndices.size(); } + int GetNumberOfMidiOutputPorts() const { return outputMidiPortIndices.size(); } + + virtual void SetAudioInputBuffer(int index, float *buffer); + float *GetAudioInputBuffer(int index) const { return this->inputAudioBuffers[index]; } + + void SetAudioInputBuffer(float *buffer); + void SetAudioInputBuffers(float *left, float *right); + + virtual void SetAudioOutputBuffer(int index, float *buffer); + float *GetAudioOutputBuffer(int index) const { return this->outputAudioBuffers[index]; } + + void SetAtomInputBuffer(int index, void *buffer); + void *GetAtomInputBuffer(int index) const { return this->inputAtomBuffers[index]; } + + void SetAtomOutputBuffer(int index, void *buffer); + void *GetAtomOutputBuffer(int index) const { return this->outputAtomBuffers[index]; } + + virtual int GetControlIndex(const std::string &symbol) const; + + virtual void SetControl(int index, float value) + { + if (index == -1) + { + this->bypass = value != 0; + } else { + controlValues[index] = value; + } + } + virtual float GetControlValue(int index) const { + if (index == -1) + { + return this->bypass? 1: 0; + } + return controlValues[index]; + } + + + virtual float GetOutputControlValue(int portIndex) const + { + return controlValues[portIndex]; + } + + virtual void SetBypass(bool bypass) + { + if (bypass != this->bypass) + { + this->bypass = bypass; + BypassTo(bypass? 1.0f: 0.0f); + } + + } + int GetNumberOfInputs() const + { + return this->inputAudioPortIndices.size(); + } + int GetNumberOfOutputs() const + { + return this->outputAudioPortIndices.size(); + } + int GetNumberOfMidiInputs() const + { + return this->inputMidiPortIndices.size(); + } + + void Activate(); + void Run(uint32_t samples); + void Deactivate(); + }; + +} // namespace \ No newline at end of file diff --git a/src/Lv2EventBufferWriter.cpp b/src/Lv2EventBufferWriter.cpp new file mode 100644 index 0000000..5115f3a --- /dev/null +++ b/src/Lv2EventBufferWriter.cpp @@ -0,0 +1,15 @@ +#include "pch.h" +#include "Lv2EventBufferWriter.hpp" +#include "Lv2Host.hpp" + + +using namespace pipedal; + + +Lv2EventBufferUrids::Lv2EventBufferUrids(IHost *pHost) +{ + atom_Chunk = pHost->GetLv2Urid(LV2_ATOM__Chunk); + atom_Sequence = pHost->GetLv2Urid(LV2_ATOM__Sequence); + midi_Event = pHost->GetLv2Urid(LV2_MIDI__MidiEvent); +} + diff --git a/src/Lv2EventBufferWriter.hpp b/src/Lv2EventBufferWriter.hpp new file mode 100644 index 0000000..a2b951d --- /dev/null +++ b/src/Lv2EventBufferWriter.hpp @@ -0,0 +1,153 @@ +#pragma once + +/* + Based on lv2_evbuf.h/lv2_evbuf.c in https://raw.githubusercontent.com/drobilla/jalv/master/src/lv2_evbuf.h + + Copyright 2008-2014 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include + +namespace pipedal +{ + class IHost; + class Lv2EventBufferUrids + { + public: + Lv2EventBufferUrids(IHost *pHost); + + LV2_URID atom_Chunk; + LV2_URID atom_Sequence; + LV2_URID midi_Event; + }; + + class Lv2EventBufferWriter + { + const Lv2EventBufferUrids &urids; + LV2_Atom_Sequence *evbuf; + + size_t bufferSize; + size_t offset; + size_t padSize(size_t size) const + { + return (size + 7) & (~7); + } + + size_t size() const { + assert(evbuf->atom.type != urids.atom_Sequence + || evbuf->atom.size >= sizeof(LV2_Atom_Sequence_Body)); + return evbuf->atom.type == urids.atom_Sequence + ? evbuf->atom.size - sizeof(LV2_Atom_Sequence_Body) + : 0; + } + + public: + Lv2EventBufferWriter(const Lv2EventBufferUrids &urids) + : urids(urids), + evbuf(nullptr), + bufferSize(0), + offset(0) + { + } + + Lv2EventBufferWriter(const Lv2EventBufferUrids &urids, uint8_t *buffer, size_t size) + : urids(urids), + evbuf((LV2_Atom_Sequence *)buffer), + bufferSize(size), + offset(0) + { + this->evbuf->atom.size = sizeof(LV2_Atom_Sequence_Body); + this->evbuf->atom.type = urids.atom_Sequence; + } + void Reset(uint8_t *buffer, size_t size) + { + this->evbuf = (LV2_Atom_Sequence*)buffer; + + this->bufferSize = size; + this->offset = 0; + this->evbuf->atom.size = sizeof(LV2_Atom_Sequence_Body); + this->evbuf->atom.type = urids.atom_Sequence; + } + + class LV2_EvBuf_Iterator + { + public: + Lv2EventBufferWriter *writer; + size_t offset; + }; + + LV2_EvBuf_Iterator begin() const + { + LV2_EvBuf_Iterator iter = {const_cast(this), 0}; + return iter; + } + + LV2_EvBuf_Iterator end() const + { + LV2_EvBuf_Iterator iter = {const_cast(this), padSize(size())}; + return iter; + } + bool isValid(const LV2_EvBuf_Iterator &iterator) const + { + return iterator.offset < size(); + } + + bool write( + LV2_EvBuf_Iterator &iterator, + uint32_t frameOffset, + uint32_t type, + size_t size, + const void*data + ) + { + LV2_Atom_Sequence *aseq = evbuf; + if (bufferSize - sizeof(LV2_Atom) - evbuf->atom.size < + sizeof(LV2_Atom_Event) + size) + { + return false; + } + + LV2_Atom_Event *aev = (LV2_Atom_Event *)((char *)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq) + iterator.offset); + + aev->time.frames = frameOffset; + aev->body.type = type; + aev->body.size = size; + memcpy(LV2_ATOM_BODY(&aev->body), data, size); + + size = padSize(sizeof(LV2_Atom_Event) + size); + aseq->atom.size += size; + iterator.offset += size; + + return true; + } + bool writeMidiEvent( + LV2_EvBuf_Iterator &iterator, + int32_t frameOffset, + size_t midiSize, + void *midiData + ) + { + + write(iterator,frameOffset,urids.midi_Event,midiSize,midiData); + return false; + } + }; + +} // namespace. \ No newline at end of file diff --git a/src/Lv2Host.cpp b/src/Lv2Host.cpp new file mode 100644 index 0000000..abbfd42 --- /dev/null +++ b/src/Lv2Host.cpp @@ -0,0 +1,1165 @@ +#include "pch.h" +#include "Lv2Host.hpp" +#include +#include +#include +#include +#include "Lv2Log.hpp" +#include +#include "PedalBoard.hpp" +#include "Lv2Effect.hpp" +#include "Lv2PedalBoard.hpp" +#include "OptionsFeature.hpp" +#include "JackConfiguration.hpp" +#include "lv2/urid/urid.h" +#include "lv2/core/lv2.h" +#include "lv2/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h" +#include "lv2/lv2plug.in/ns/ext/presets/presets.h" +#include "lv2/lv2plug.in/ns/ext/port-props/port-props.h" +#include "lv2/lv2plug.in/ns/extensions/units/units.h" +#include "lv2/lv2plug.in/ns/ext/port-groups/port-groups.h" +#include +#include "PiPedalException.hpp" +#include "Locale.hpp" + +using namespace pipedal; + +#define MAP_CHECK() \ + { \ + if (GetPluginClass("http://lv2plug.in/ns/lv2core#Plugin") == nullptr) \ + throw PiPedalStateException("Map is broken"); \ + } + +#define PLUGIN_MAP_CHECK() \ + { \ + if (pHost->GetPluginClass("http://lv2plug.in/ns/lv2core#Plugin") == nullptr) \ + throw PiPedalStateException("Map is broken"); \ + } + +#define P_LV2_CORE_URI "http://lv2plug.in/ns/lv2core#" +#define P_LV2_PPROPS "http://lv2plug.in/ns/ext/port-props#" + +namespace pipedal +{ + static const char *LV2_AUDIO_PORT = P_LV2_CORE_URI "AudioPort"; + static const char *LV2_PLUGIN = P_LV2_CORE_URI "Plugin"; + static const char *LV2_CONTROL_PORT = P_LV2_CORE_URI "ControlPort"; + static const char *LV2_INPUT_PORT = P_LV2_CORE_URI "InputPort"; + static const char *LV2_OUTPUT_PORT = P_LV2_CORE_URI "OutputPort"; + static const char *LV2_INTEGER = P_LV2_CORE_URI "integer"; + static const char *LV2_ENUMERATION = P_LV2_CORE_URI "enumeration"; + static const char *LV2_PORT_LOGARITHMIC = P_LV2_PPROPS "logarithmic"; + static const char *LV2_PORT_RANGE_STEPS = P_LV2_PPROPS "rangeSteps"; + static const char *LV2_PORT_TRIGGER = P_LV2_PPROPS "trigger"; + static const char *LV2_PORT_DISPLAY_PRIORITY = P_LV2_PPROPS "displayPriority"; + static const char *LV2_MIDI_PLUGIN = "http://lv2plug.in/ns/lv2core#MIDIPlugin"; + + static const char *LV2_ATOM_PORT = "http://lv2plug.in/ns/ext/atom#AtomPort"; + static const char *LV2_ATOM_SEQUENCE = "http://lv2plug.in/ns/ext/atom#Sequence"; + static const char *LV2_ATOM_SOUND = "http://lv2plug.in/ns/ext/atom#Sound"; + static const char *LV2_ATOM_VECTOR = "http://lv2plug.in/ns/ext/atom#Vector"; + static const char *LV2_ATOM_STRING = "http://lv2plug.in/ns/ext/atom#String"; + static const char *LV2_MIDI_EVENT = "http://lv2plug.in/ns/ext/midi#MidiEvent"; + static const char *LV2_DESIGNATION = "http://lv2plug.in/ns/lv2core#Designation"; + + + class Lv2Host::Urids { + public: + Urids(MapFeature &mapFeature) + { + atom_Float = mapFeature.GetUrid(LV2_ATOM__Float); + } + LV2_URID atom_Float; + }; +} + +static std::string nodeAsString(const LilvNode *node) +{ + if (node == nullptr) + { + return ""; + } + if (lilv_node_is_uri(node)) + { + return lilv_node_as_uri(node); + } + if (lilv_node_is_string(node)) + { + return lilv_node_as_string(node); + } + if (lilv_node_is_blank(node)) + { + return ""; + } + return "#TypeError"; +} +static float nodeAsFloat(const LilvNode *node, float default_ = 0) +{ + if (node == nullptr) + { + return default_; + } + if (lilv_node_is_float(node)) + { + return lilv_node_as_float(node); + } + if (lilv_node_is_int(node)) + { + return lilv_node_as_int(node); + } + if (lilv_node_is_blank(node)) + { + return default_; + } + return default_; +} + +class NodeAutoFree +{ + LilvNode *node = nullptr; + + // const LilvNode* returns must not be freed, by convention. + NodeAutoFree(const LilvNode *node) + { + } + +public: + NodeAutoFree() + { + this->node = nullptr; + } + NodeAutoFree(LilvNode *node) + { + this->node = node; + } + operator const LilvNode *() + { + return this->node; + } + + LilvNode **operator&() + { + return &(this->node); + } + + operator bool() + { + return this->node != nullptr; + } + + float as_float(float defaultValue = 0) + { + return nodeAsFloat(this->node, defaultValue); + } + int as_int() + { + if (node == nullptr) + return 0; + if (lilv_node_is_int(node)) + return lilv_node_as_int(node); + return 0; + } + bool as_bool() + { + if (node == nullptr) + return false; + if (lilv_node_is_int(node)) + return lilv_node_as_bool(node); + return false; + } + std::string as_string() + { + return nodeAsString(this->node); + } + + ~NodeAutoFree() + { + if (this->node != nullptr) + { + lilv_free(this->node); + this->node = nullptr; + } + } +}; + +Lv2Host::Lv2Host() +{ + pWorld = nullptr; + + LV2_Feature **features = new LV2_Feature *[10]; + features[0] = const_cast(mapFeature.GetMapFeature()); + features[1] = const_cast(mapFeature.GetUnmapFeature()); + + logFeature.Prepare(&mapFeature); + features[2] = const_cast(logFeature.GetFeature()); + optionsFeature.Prepare(mapFeature, 44100, this->GetMaxAudioBufferSize(), this->GetAtomBufferSize()); + features[3] = const_cast(optionsFeature.GetFeature()); + features[4] = nullptr; + + this->lv2Features = features; + this->urids = new Urids(mapFeature); +} + +void Lv2Host::OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings) +{ + this->sampleRate = configuration.GetSampleRate(); + if (configuration.isValid()) + { + this->numberOfAudioInputChannels = settings.GetInputAudioPorts().size(); + this->numberOfAudioOutputChannels = settings.getOutputAudioPorts().size(); + this->maxBufferSize = configuration.GetBlockLength(); + optionsFeature.Prepare(this->mapFeature, configuration.GetSampleRate(), configuration.GetBlockLength(), GetAtomBufferSize()); + } +} + +Lv2Host::~Lv2Host() +{ + delete[] lv2Features; + free_world(); + delete urids; +} + +void Lv2Host::free_world() +{ + if (pWorld) + { + lilv_world_free(pWorld); + pWorld = nullptr; + } +} +std::shared_ptr Lv2Host::GetPluginClass(const std::string &uri) const +{ + auto it = this->classesMap.find(uri); + if (it == this->classesMap.end()) + return nullptr; + return (*it).second; +} + +void Lv2Host::AddJsonClassesToMap(std::shared_ptr pluginClass) +{ + this->classesMap[pluginClass->uri()] = pluginClass; + for (int i = 0; i < pluginClass->children_.size(); ++i) + { + std::shared_ptr child = pluginClass->children_[i]; + AddJsonClassesToMap(pluginClass->children_[i]); + child->parent_ = pluginClass.get(); + } +} +void Lv2Host::LoadPluginClassesFromJson(std::filesystem::path jsonFile) +{ + std::ifstream f(jsonFile); + json_reader reader(f); + + std::shared_ptr classes; + reader.read(&classes); + + AddJsonClassesToMap(classes); + this->classesLoaded = true; + + MAP_CHECK(); +} + +std::shared_ptr Lv2Host::GetPluginClass(const LilvPluginClass *pClass) +{ + MAP_CHECK(); + + std::string uri = nodeAsString(lilv_plugin_class_get_uri(pClass)); + std::shared_ptr pResult = this->classesMap[uri]; + return pResult; +} +std::shared_ptr Lv2Host::MakePluginClass(const LilvPluginClass *pClass) +{ + std::string uri = nodeAsString(lilv_plugin_class_get_uri(pClass)); + + std::shared_ptr pResult = this->classesMap[uri]; + if (!pResult) + { + const LilvNode *parentNode = lilv_plugin_class_get_parent_uri(pClass); + std::string parent_uri = nodeAsString(parentNode); + + std::string name = nodeAsString(lilv_plugin_class_get_label(pClass)); + + std::shared_ptr result = std::make_shared( + name.c_str(), uri.c_str(), parent_uri.c_str()); + + classesMap[uri] = std::move(result); + } + return pResult; +} + +void Lv2Host::LoadPluginClassesFromLilv() +{ + const auto classes = lilv_world_get_plugin_classes(pWorld); + + LILV_FOREACH(plugin_classes, iPluginClass, classes) + { + const LilvPluginClass *pClass = lilv_plugin_classes_get(classes, iPluginClass); + // Get it to prepopulate the map. + MakePluginClass(pClass); + } + for (auto value : classesMap) + { + std::shared_ptr lv2Class{value.second}; + + auto t = GetPluginClass(lv2Class->uri()); + + if (lv2Class && lv2Class->parent_uri().size() != 0) + { + std::shared_ptr parentClass = GetPluginClass(lv2Class->parent_uri()); + if (parentClass) + { + Lv2PluginClass *ccClass = const_cast(lv2Class.get()); + ccClass->set_parent(parentClass); + Lv2PluginClass *ccParentClass = parentClass.get(); + ccParentClass->add_child(lv2Class); + } + } + } +} + +void Lv2Host::Load(const char *lv2Path) +{ + this->plugins_.clear(); + this->ui_plugins_.clear(); + if (!classesLoaded) + { + this->classesMap.clear(); + } + + free_world(); + + setenv("LV2_PATH", lv2Path, true); + pWorld = lilv_world_new(); + lilv_world_load_all(pWorld); + + if (!classesLoaded) + { + LoadPluginClassesFromLilv(); + } + + const LilvPlugins *plugins = lilv_world_get_all_plugins(pWorld); + + LILV_FOREACH(plugins, iPlugin, plugins) + { + const LilvPlugin *lilvPlugin = lilv_plugins_get(plugins, iPlugin); + + std::shared_ptr pluginInfo = std::make_shared(this, lilvPlugin); + + Lv2Log::debug("Plugin: " + pluginInfo->name()); + + if (pluginInfo->hasCvPorts()) + { + Lv2Log::debug("Plugin %s (%s) skipped. (Has CV ports).", pluginInfo->name().c_str(), pluginInfo->uri().c_str()); + } + else if (pluginInfo->plugin_class() == LV2_MIDI_PLUGIN) + { + Lv2Log::debug("Plugin %s (%s) skipped. (MIDI Plugin).", pluginInfo->name().c_str(), pluginInfo->uri().c_str()); + } + else if (!pluginInfo->is_valid()) + { + auto &ports = pluginInfo->ports(); + for (int i = 0; i < ports.size(); ++i) + { + auto &port = ports[i]; + if (!port->is_valid()) + { + Lv2Log::debug("Plugin port %s:%s is invalid.", pluginInfo->name().c_str(), port->name().c_str()); + } + } + Lv2Log::debug("Plugin %s (%s) skipped. Not valid.", pluginInfo->name().c_str(), pluginInfo->uri().c_str()); + } + else + { + this->plugins_.push_back(pluginInfo); + } + } + + auto compare = []( + const std::shared_ptr &left, + const std::shared_ptr &right) + { + const char *pb1 = left->name().c_str(); + const char *pb2 = right->name().c_str(); + return Locale::collation.compare( + pb1, pb1 + left->name().size(), + pb2, pb2 + right->name().size()) < 0; + }; + std::sort(this->plugins_.begin(), this->plugins_.end(), compare); + + for (auto plugin : this->plugins_) + { + Lv2PluginUiInfo info(this, plugin.get()); + if (plugin->is_valid()) + { + if (info.audio_inputs() == 0) + { + Lv2Log::debug("Plugin %s (%s) skipped. No audio inputs.", plugin->name().c_str(), plugin->uri().c_str()); + } + else if (info.audio_outputs() == 0) + { + Lv2Log::debug("Plugin %s (%s) skipped. No audio outputs.", plugin->name().c_str(), plugin->uri().c_str()); + } + else + { + ui_plugins_.push_back(std::move(info)); + } + } + } +}; + +class NodesAutoFree +{ + LilvNodes *nodes; + + // const LilvNode* returns must not be freed, by convention. + NodesAutoFree(const LilvNodes *nodes) + { + } + +public: + NodesAutoFree(LilvNodes *nodes) + { + this->nodes = nodes; + } + operator const LilvNodes *() + { + return this->nodes; + } + operator bool() + { + return this->nodes != nullptr; + } + ~NodesAutoFree() + { + lilv_nodes_free(this->nodes); + } +}; + +static std::vector nodeAsStringArray(const LilvNodes *nodes) +{ + std::vector result; + LILV_FOREACH(nodes, iNode, nodes) + { + result.push_back(nodeAsString(lilv_nodes_get(nodes, iNode))); + } + return result; +} + +static const char *RDFS_COMMENT_URI = "http://www.w3.org/2000/01/rdf-schema#" + "comment"; + +static LilvNode *get_comment(LilvWorld *pWorld, const std::string &uri) +{ + NodeAutoFree uriNode = lilv_new_uri(pWorld, uri.c_str()); + NodeAutoFree rdfsComment = lilv_new_uri(pWorld, RDFS_COMMENT_URI); + LilvNode *result = lilv_world_get(pWorld, uriNode, rdfsComment, nullptr); + return result; +} + +static bool ports_sort_compare(std::shared_ptr &p1, const std::shared_ptr &p2) +{ + return p1->index() < p2->index(); +} + +Lv2PluginInfo::Lv2PluginInfo(Lv2Host *lv2Host, const LilvPlugin *pPlugin) +{ + this->uri_ = nodeAsString(lilv_plugin_get_uri(pPlugin)); + + NodeAutoFree name = (lilv_plugin_get_name(pPlugin)); + this->name_ = nodeAsString(name); + + NodeAutoFree author_name = (lilv_plugin_get_author_name(pPlugin)); + this->author_name_ = nodeAsString(author_name); + + NodeAutoFree author_homepage = (lilv_plugin_get_author_homepage(pPlugin)); + this->author_homepage_ = nodeAsString(author_homepage); + + const LilvPluginClass *pClass = lilv_plugin_get_class(pPlugin); + this->plugin_class_ = nodeAsString(lilv_plugin_class_get_uri(pClass)); + + NodesAutoFree required_features = lilv_plugin_get_required_features(pPlugin); + this->required_features_ = nodeAsStringArray(required_features); + + NodesAutoFree supported_features = lilv_plugin_get_supported_features(pPlugin); + this->supported_features_ = nodeAsStringArray(supported_features); + + NodesAutoFree optional_features = lilv_plugin_get_optional_features(pPlugin); + this->optional_features_ = nodeAsStringArray(optional_features); + + NodesAutoFree extensions = lilv_plugin_get_extension_data(pPlugin); + this->extensions_ = nodeAsStringArray(extensions); + + NodeAutoFree comment = get_comment(lv2Host->pWorld, this->uri_); + this->comment_ = nodeAsString(comment); + + uint32_t ports = lilv_plugin_get_num_ports(pPlugin); + + bool isValid = true; + std::vector portGroups; + + for (uint32_t i = 0; i < ports; ++i) + { + const LilvPort *pPort = lilv_plugin_get_port_by_index(pPlugin, i); + + std::shared_ptr portInfo{new Lv2PortInfo(lv2Host, pPlugin, pPort)}; + if (!portInfo->is_valid()) + { + isValid = false; + } + const auto &portGroup = portInfo->port_group(); + if (portGroup.size() != 0) + { + if (std::find(portGroups.begin(), portGroups.end(), portGroup) == portGroups.end()) + { + portGroups.push_back(portGroup); + } + } + ports_.push_back(std::move(portInfo)); + } + + for (auto &portGroup : portGroups) + { + port_groups_.push_back(std::make_shared(lv2Host, portGroup)); + } + + for (int i = 0; i < this->required_features_.size(); ++i) + { + if (!this->IsSupportedFeature(this->required_features_[i])) + { + Lv2Log::debug("%s (%s) requires feature %s.", this->name_.c_str(), this->uri_.c_str(), this->required_features_[i].c_str()); + isValid = false; + } + } + std::sort(ports_.begin(), ports_.end(), ports_sort_compare); + this->is_valid_ = isValid; +} + +std::vector supportedFeatures = { + LV2_URID__map, + LV2_URID__unmap, + LV2_LOG__log, + LV2_WORKER__schedule, + LV2_OPTIONS__options, + LV2_BUF_SIZE__boundedBlockLength, + LV2_BUF_SIZE__fixedBlockLength, + LV2_BUF_SIZE__powerOf2BlockLength, + LV2_CORE__isLive, + +}; + +bool Lv2PluginInfo::IsSupportedFeature(const std::string &feature) const +{ + for (int i = 0; i < supportedFeatures.size(); ++i) + { + if (supportedFeatures[i] == feature) + return true; + } + return false; +} +Lv2PluginInfo::~Lv2PluginInfo() +{ +} + +bool Lv2PortInfo::is_a(Lv2Host *lv2Plugins, const char *classUri) +{ + return classes_.is_a(lv2Plugins, classUri); +} + +static float getFloat(const LilvNode *pNode) +{ + if (lilv_node_is_float(pNode)) + { + return lilv_node_as_float(pNode); + } + if (lilv_node_is_int(pNode)) + { + return lilv_node_as_int(pNode); + } + throw std::invalid_argument("Invalid float node."); +} + +static bool scale_points_sort_compare(const Lv2ScalePoint &v1, const Lv2ScalePoint &v2) +{ + return v1.value() < v2.value(); +} +Lv2PortInfo::Lv2PortInfo(Lv2Host *plugins, const LilvPlugin *plugin, const LilvPort *pPort) +{ + auto pWorld = plugins->pWorld; + index_ = lilv_port_get_index(plugin, pPort); + symbol_ = nodeAsString(lilv_port_get_symbol(plugin, pPort)); + + NodeAutoFree name = lilv_port_get_name(plugin, pPort); + name_ = nodeAsString(name); + + classes_ = plugins->GetPluginPortClass(plugin, pPort); + + NodeAutoFree minNode, maxNode, defaultNode; + min_value_ = 0; + max_value_ = 1; + default_value_ = 0; + lilv_port_get_range(plugin, pPort, &defaultNode, &minNode, &maxNode); + if (defaultNode) + { + default_value_ = getFloat(defaultNode); + } + if (minNode) + { + min_value_ = getFloat(minNode); + } + if (maxNode) + { + max_value_ = getFloat(maxNode); + } + if (default_value_ > max_value_) + default_value_ = max_value_; + if (default_value_ < min_value_) + default_value_ = min_value_; + + NodeAutoFree logarithic_uri = lilv_new_uri(pWorld, LV2_PORT_LOGARITHMIC); + this->is_logarithmic_ = lilv_port_has_property(plugin, pPort, logarithic_uri); + + NodeAutoFree display_priority_uri = lilv_new_uri(pWorld, LV2_PORT_DISPLAY_PRIORITY); + NodesAutoFree priority_nodes = lilv_port_get_value(plugin, pPort, display_priority_uri); + + this->display_priority_ = -1; + if (priority_nodes) + { + auto priority_node = lilv_nodes_get_first(priority_nodes); + if (priority_node) + { + this->display_priority_ = lilv_node_as_int(priority_node); + } + } + + NodeAutoFree range_steps_uri = lilv_new_uri(pWorld, LV2_PORT_RANGE_STEPS); + NodesAutoFree range_steps_nodes = lilv_port_get_value(plugin, pPort, range_steps_uri); + this->range_steps_ = 0; + if (range_steps_nodes) + { + auto range_steps_node = lilv_nodes_get_first(range_steps_nodes); + if (range_steps_node) + { + this->range_steps_ = lilv_node_as_int(range_steps_node); + } + } + NodeAutoFree integer_property_uri = lilv_new_uri(pWorld, LV2_INTEGER); + this->integer_property_ = lilv_port_has_property(plugin, pPort, integer_property_uri); + + NodeAutoFree enumeration_property_uri = lilv_new_uri(pWorld, LV2_ENUMERATION); + this->enumeration_property_ = lilv_port_has_property(plugin, pPort, enumeration_property_uri); + + NodeAutoFree toggle_property_uri = lilv_new_uri(pWorld, LV2_CORE__toggled); + this->toggled_property_ = lilv_port_has_property(plugin, pPort, toggle_property_uri); + + NodeAutoFree not_on_gui_property_uri = lilv_new_uri(pWorld, LV2_PORT_PROPS__notOnGUI); + this->not_on_gui_ = lilv_port_has_property(plugin, pPort, not_on_gui_property_uri); + + LilvScalePoints *pScalePoints = lilv_port_get_scale_points(plugin, pPort); + LILV_FOREACH(scale_points, iSP, pScalePoints) + { + const LilvScalePoint *pSP = lilv_scale_points_get(pScalePoints, iSP); + float value = nodeAsFloat(lilv_scale_point_get_value(pSP)); + auto label = nodeAsString(lilv_scale_point_get_label(pSP)); + scale_points_.push_back(Lv2ScalePoint(value, label)); + } + lilv_scale_points_free(pScalePoints); + + // sort is what we want, but the implementation is broken in g++ 8.3 + + std::sort(scale_points_.begin(), scale_points_.end(), scale_points_sort_compare); + + is_input_ = is_a(plugins, LV2_INPUT_PORT); + is_output_ = is_a(plugins, LV2_OUTPUT_PORT); + + is_control_port_ = is_a(plugins, LV2_CORE__ControlPort); + is_audio_port_ = is_a(plugins, LV2_CORE__AudioPort); + is_atom_port_ = is_a(plugins, LV2_ATOM_PORT); + is_cv_port_ = is_a(plugins, LV2_CORE__CVPort); + + NodeAutoFree midiEventNode = lilv_new_uri(plugins->pWorld, LV2_MIDI_EVENT); + supports_midi_ = lilv_port_supports_event(plugin, pPort, midiEventNode); + + NodeAutoFree designationNode = lilv_new_uri(plugins->pWorld, LV2_DESIGNATION); + NodeAutoFree designationValue = lilv_port_get(plugin, pPort, designationNode); + designation_ = nodeAsString(designationValue); + + NodeAutoFree portGroupUri = lilv_new_uri(plugins->pWorld, LV2_PORT_GROUPS__group); + NodeAutoFree portGroup_value = lilv_port_get(plugin, pPort, portGroupUri); + port_group_ = nodeAsString(portGroup_value); + + NodeAutoFree unitsUri = lilv_new_uri(plugins->pWorld, LV2_UNITS__unit); + NodeAutoFree unitsValueUri = lilv_port_get(plugin, pPort, unitsUri); + this->units_ = UriToUnits(nodeAsString(unitsValueUri)); + + + NodeAutoFree bufferType_uri = lilv_new_uri(pWorld, LV2_ATOM__bufferType); + NodeAutoFree bufferType = lilv_port_get(plugin, pPort, bufferType_uri); + + this->buffer_type_ = ""; + if (bufferType) + { + this->buffer_type_ = nodeAsString(bufferType); + } + + is_valid_ = is_control_port_ || + ((is_input_ || is_output_) && (is_audio_port_ || is_atom_port_ || is_cv_port_)); +} + +Lv2PluginClasses Lv2Host::GetPluginPortClass(const LilvPlugin *lilvPlugin, const LilvPort *lilvPort) +{ + std::vector result; + const LilvNodes *nodes = lilv_port_get_classes(lilvPlugin, lilvPort); + if (nodes != nullptr) + { + LILV_FOREACH(nodes, iNode, nodes) + { + const LilvNode *node = lilv_nodes_get(nodes, iNode); + std::string classUri = nodeAsString(node); + result.push_back(classUri); + } + } + return Lv2PluginClasses(result); +} + +bool Lv2PluginClass::is_a(const std::string &classUri) const +{ + if (this->uri_ == classUri) + return true; + if (parent_) + { + return parent_->is_a(classUri); + } + // some classes have parent uris that are not themselves + // classes because the class tree is incomplete. + if (this->parent_uri_ == classUri) + { + return true; + } + return false; +} +bool Lv2PluginClasses::is_a(Lv2Host *lv2Plugins, const char *classUri) const +{ + std::string classUri_(classUri); + for (auto i : classes_) + { + if (lv2Plugins->is_a(classUri_, i)) + { + return true; + } + } + return false; +} + +bool Lv2Host::is_a(const std::string &class_, const std::string &target_class) +{ + if (class_ == target_class) + return true; + std::shared_ptr pClass = this->GetPluginClass(target_class); + if (pClass) + { + return pClass->is_a(class_); + } + return false; +} + +Lv2PluginUiInfo::Lv2PluginUiInfo(Lv2Host *pHost, const Lv2PluginInfo *plugin) + : uri_(plugin->uri()), + name_(plugin->name()), + author_name_(plugin->author_name()), + author_homepage_(plugin->author_homepage()), + plugin_type_(uri_to_plugin_type(plugin->plugin_class())), + audio_inputs_(0), + audio_outputs_(0), + description_(plugin->comment()), + has_midi_input_(false), + has_midi_output_(false) +{ + PLUGIN_MAP_CHECK(); + auto pluginClass = pHost->GetPluginClass(plugin->plugin_class()); + if (pluginClass) + { + this->plugin_display_type_ = pluginClass->display_name(); + } + else + { + PLUGIN_MAP_CHECK(); + this->plugin_display_type_ = "Plugin"; + Lv2Log::error("%s: Unknown plugin type: %s", plugin->uri().c_str(), plugin->plugin_class().c_str()); + } + for (auto port : plugin->ports()) + { + if (port->is_input()) + { + if (port->is_control_port() && port->is_input()) + { + controls_.push_back(Lv2PluginUiControlPort(plugin, port.get())); + } + else if (port->is_atom_port()) + { + if (port->supports_midi()) + { + has_midi_input_ = true; + } + } + else if (port->is_audio_port()) + { + ++audio_inputs_; + } + } + else if (port->is_output()) + { + if (port->is_atom_port() && port->supports_midi()) + { + this->has_midi_output_ = true; + } + else if (port->is_audio_port()) + { + ++audio_outputs_; + } + } + } + for (auto &portGroup : plugin->port_groups()) + { + this->port_groups_.push_back(Lv2PluginUiPortGroup(portGroup.get())); + } +} + +std::shared_ptr Lv2Host::GetLv2PluginClass() const +{ + return this->GetPluginClass(LV2_PLUGIN); +} + +std::shared_ptr Lv2Host::GetPluginInfo(const std::string &uri) const +{ + for (auto i = this->plugins_.begin(); i != this->plugins_.end(); ++i) + { + if ((*i)->uri() == uri) + { + return (*i); + } + } + return nullptr; +} + + +Lv2PedalBoard *Lv2Host::CreateLv2PedalBoard(const PedalBoard &pedalBoard) +{ + Lv2PedalBoard *pPedalBoard = new Lv2PedalBoard(); + try + { + pPedalBoard->Prepare(this, pedalBoard); + return pPedalBoard; + } + catch (const std::exception &) + { + delete pPedalBoard; + throw; + } +} + + +struct StateCallbackData { + Lv2Host*pHost; + std::vector *pResult; +}; + +void Lv2Host::fn_LilvSetPortValueFunc(const char* port_symbol, + void* user_data, + const void* value, + uint32_t size, + uint32_t type) +{ + StateCallbackData *pData = (StateCallbackData*)user_data; + Lv2Host *pHost = pData->pHost; + std::vector *pResult = pData->pResult; + LV2_URID valueType = (LV2_URID)type; + if (valueType != pHost->urids->atom_Float) + { + throw PiPedalStateException("Preset format not supported."); + } + pResult->push_back(ControlValue(port_symbol,*(float*)value)); + +} + + + +std::vector Lv2Host::LoadPluginPreset(PedalBoardItem*pedalBoardItem, const std::string&presetUri) +{ + + std::vector result; + + const LilvPlugins*plugins = lilv_world_get_all_plugins(this->pWorld); + + NodeAutoFree uriNode = lilv_new_uri(pWorld, pedalBoardItem->uri().c_str()); + + lilv_world_load_resource(pWorld, uriNode); + + const LilvPlugin * plugin = lilv_plugins_get_by_uri (plugins, uriNode); + if (plugin == nullptr) + { + throw PiPedalStateException("No such plugin."); + } + + NodeAutoFree pset_Preset = lilv_new_uri(pWorld, LV2_PRESETS__Preset); + NodeAutoFree rdfs_label = lilv_new_uri(pWorld, LILV_NS_RDFS "label"); + + + LilvNodes* presets = lilv_plugin_get_related(plugin, pset_Preset); + LILV_FOREACH(nodes, i, presets) { + const LilvNode* preset = lilv_nodes_get(presets, i); + lilv_world_load_resource(pWorld, preset); + + std::string thisPresetUri = nodeAsString(preset); + if (presetUri == thisPresetUri) + { + + /*********************************/ + + + // NodeAutoFree uriNode = lilv_new_uri(pWorld, presetUri.c_str()); + + auto lilvState = lilv_state_new_from_world(pWorld, GetLv2UridMap(), preset); + + if (lilvState == nullptr) + { + throw PiPedalStateException("Preset not found."); + } + + + StateCallbackData cbData; + cbData.pHost = this; + cbData.pResult = &result; + auto n = lilv_state_get_num_properties(lilvState); + lilv_state_emit_port_values (lilvState, fn_LilvSetPortValueFunc,&cbData); + + lilv_state_free(lilvState); + break; + + /*********************************/ + } + + } + lilv_nodes_free(presets); + + return result; +} + +std::vector Lv2Host::GetPluginPresets(const std::string &pluginUri) +{ + std::vector result; + + const LilvPlugins*plugins = lilv_world_get_all_plugins(this->pWorld); + + NodeAutoFree uriNode = lilv_new_uri(pWorld, pluginUri.c_str()); + + lilv_world_load_resource(pWorld, uriNode); + + const LilvPlugin * plugin = lilv_plugins_get_by_uri (plugins, uriNode); + if (plugin == nullptr) + { + throw PiPedalStateException("No such plugin."); + } + + NodeAutoFree pset_Preset = lilv_new_uri(pWorld, LV2_PRESETS__Preset); + NodeAutoFree rdfs_label = lilv_new_uri(pWorld, LILV_NS_RDFS "label"); + + + LilvNodes* presets = lilv_plugin_get_related(plugin, pset_Preset); + LILV_FOREACH(nodes, i, presets) { + const LilvNode* preset = lilv_nodes_get(presets, i); + lilv_world_load_resource(pWorld, preset); + + LilvNodes* labels = lilv_world_find_nodes( + pWorld, preset, rdfs_label, NULL); + if (labels) { + const LilvNode* label = lilv_nodes_get_first(labels); + std::string presetName = nodeAsString(label); + result.push_back(Lv2PluginPreset(nodeAsString(preset),presetName)); + lilv_nodes_free(labels); + } else { + std::stringstream s; + s << "Preset <" << nodeAsString(lilv_nodes_get(presets,i)) << "> has no rdfs:label."; + + Lv2Log::warning(s.str()); + } + } + lilv_nodes_free(presets); + + auto compare = [] (const Lv2PluginPreset&left, const Lv2PluginPreset&right) + { + return Locale::collation.compare( + left.name_.c_str(), + left.name_.c_str()+left.name_.size(), + right.name_.c_str(), + right.name_.c_str()+right.name_.size()) < 0; + }; + + std::sort(result.begin(),result.end(),compare); + return result; + +} + + +Lv2Effect *Lv2Host::CreateEffect(const PedalBoardItem &pedalBoardItem) +{ + + auto info = this->GetPluginInfo(pedalBoardItem.uri()); + if (!info) return nullptr; + + return new Lv2Effect(this, info, pedalBoardItem); +} + +Lv2PortGroup::Lv2PortGroup(Lv2Host *lv2Host, const std::string &groupUri) +{ + LilvWorld *pWorld = lv2Host->pWorld; + + NodeAutoFree symbolUri = lilv_new_uri(pWorld, LV2_CORE__symbol); + NodeAutoFree nameUri = lilv_new_uri(pWorld, LV2_CORE__name); + this->uri_ = groupUri; + NodeAutoFree uri = lilv_new_uri(pWorld, groupUri.c_str()); + LilvNode *symbolNode = lilv_world_get(pWorld, uri, symbolUri, nullptr); + symbol_ = nodeAsString(symbolNode); + LilvNode *nameNode = lilv_world_get(pWorld, uri, nameUri, nullptr); + name_ = nodeAsString(nameNode); +} + + + +#define MAP_REF(class, name) \ + json_map::reference(#name, &class ::name##_) + +#define CONDITIONAL_MAP_REF(class, name, condition) \ + json_map::conditional_reference(#name, &class ::name##_, condition) + +json_map::storage_type Lv2PluginClasses::jmap{{ + //json_map::reference("char_", &JsonTestTarget::char_), + json_map::reference("classes", &Lv2PluginClasses::classes_), +}}; + +json_map::storage_type Lv2ScalePoint::jmap{{ + json_map::reference("value", &Lv2ScalePoint::value_), + json_map::reference("label", &Lv2ScalePoint::label_), +}}; + +json_map::storage_type Lv2PortInfo::jmap{{ + json_map::reference("index", &Lv2PortInfo::index_), + json_map::reference("symbol", &Lv2PortInfo::symbol_), + json_map::reference("index", &Lv2PortInfo::index_), + json_map::reference("name", &Lv2PortInfo::name_), + + json_map::reference("min_value", &Lv2PortInfo::min_value_), + json_map::reference("max_value", &Lv2PortInfo::max_value_), + json_map::reference("default_value", &Lv2PortInfo::default_value_), + json_map::reference("classes", &Lv2PortInfo::classes_), + + json_map::reference("scale_points", &Lv2PortInfo::scale_points_), + + json_map::reference("is_input", &Lv2PortInfo::is_input_), + json_map::reference("is_output", &Lv2PortInfo::is_output_), + + json_map::reference("is_control_port", &Lv2PortInfo::is_control_port_), + json_map::reference("is_audio_port", &Lv2PortInfo::is_audio_port_), + json_map::reference("is_atom_port", &Lv2PortInfo::is_audio_port_), + json_map::reference("is_cv_port", &Lv2PortInfo::is_cv_port_), + + json_map::reference("is_valid", &Lv2PortInfo::is_valid_), + + json_map::reference("supports_midi", &Lv2PortInfo::supports_midi_), + json_map::reference("port_group", &Lv2PortInfo::port_group_), + json_map::reference("is_logarithmic", &Lv2PortInfo::is_logarithmic_), + + MAP_REF(Lv2PortInfo, is_logarithmic), + MAP_REF(Lv2PortInfo, display_priority), + MAP_REF(Lv2PortInfo, range_steps), + MAP_REF(Lv2PortInfo, trigger), + MAP_REF(Lv2PortInfo, integer_property), + MAP_REF(Lv2PortInfo, enumeration_property), + MAP_REF(Lv2PortInfo, toggled_property), + MAP_REF(Lv2PortInfo, not_on_gui), + MAP_REF(Lv2PortInfo, buffer_type), + MAP_REF(Lv2PortInfo, port_group), + json_map::enum_reference("units", &Lv2PortInfo::units_, get_units_enum_converter()), +}}; + +json_map::storage_type Lv2PortGroup::jmap{{ + MAP_REF(Lv2PortGroup, uri), + +}}; + +json_map::storage_type Lv2PluginInfo::jmap{{ + json_map::reference("uri", &Lv2PluginInfo::uri_), + json_map::reference("name", &Lv2PluginInfo::name_), + json_map::reference("plugin_class", &Lv2PluginInfo::plugin_class_), + json_map::reference("supported_features", &Lv2PluginInfo::supported_features_), + json_map::reference("required_features", &Lv2PluginInfo::required_features_), + json_map::reference("optional_features", &Lv2PluginInfo::optional_features_), + json_map::reference("extensions", &Lv2PluginInfo::extensions_), + + json_map::reference("author_name", &Lv2PluginInfo::author_name_), + json_map::reference("author_homepage", &Lv2PluginInfo::author_homepage_), + + json_map::reference("comment", &Lv2PluginInfo::comment_), + json_map::reference("ports", &Lv2PluginInfo::ports_), + json_map::reference("port_groups", &Lv2PluginInfo::port_groups_), + json_map::reference("is_valid", &Lv2PluginInfo::is_valid_), + +}}; + +json_map::storage_type Lv2PluginUiInfo::jmap{{ + json_map::reference("uri", &Lv2PluginUiInfo::uri_), + json_map::reference("name", &Lv2PluginUiInfo::name_), + json_map::enum_reference("plugin_type", &Lv2PluginUiInfo::plugin_type_, get_plugin_type_enum_converter()), + json_map::reference("plugin_display_type", &Lv2PluginUiInfo::plugin_display_type_), + json_map::reference("author_name", &Lv2PluginUiInfo::author_name_), + json_map::reference("author_homepage", &Lv2PluginUiInfo::author_homepage_), + json_map::reference("audio_inputs", &Lv2PluginUiInfo::audio_inputs_), + json_map::reference("audio_outputs", &Lv2PluginUiInfo::audio_outputs_), + json_map::reference("description", &Lv2PluginUiInfo::description_), + json_map::reference("has_midi_input", &Lv2PluginUiInfo::has_midi_input_), + json_map::reference("has_midi_output", &Lv2PluginUiInfo::has_midi_output_), + json_map::reference("controls", &Lv2PluginUiInfo::controls_), + json_map::reference("port_groups", &Lv2PluginUiInfo::port_groups_), + +}}; + +json_map::storage_type Lv2PluginUiControlPort::jmap{{ + json_map::reference("symbol", &Lv2PluginUiControlPort::symbol_), + json_map::reference("name", &Lv2PluginUiControlPort::name_), + MAP_REF(Lv2PluginUiControlPort, index), + MAP_REF(Lv2PluginUiControlPort, min_value), + MAP_REF(Lv2PluginUiControlPort, max_value), + MAP_REF(Lv2PluginUiControlPort, default_value), + MAP_REF(Lv2PluginUiControlPort, is_logarithmic), + MAP_REF(Lv2PluginUiControlPort, display_priority), + + MAP_REF(Lv2PluginUiControlPort, range_steps), + MAP_REF(Lv2PluginUiControlPort, integer_property), + MAP_REF(Lv2PluginUiControlPort, enumeration_property), + MAP_REF(Lv2PluginUiControlPort, not_on_gui), + MAP_REF(Lv2PluginUiControlPort, toggled_property), + MAP_REF(Lv2PluginUiControlPort, scale_points), + MAP_REF(Lv2PluginUiControlPort, port_group), + + json_map::enum_reference("units", &Lv2PluginUiControlPort::units_, get_units_enum_converter()), + +}}; + +json_map::storage_type Lv2PluginClass::jmap{{ + MAP_REF(Lv2PluginClass, uri), + MAP_REF(Lv2PluginClass, display_name), + MAP_REF(Lv2PluginClass, parent_uri), + json_map::enum_reference("plugin_type", &Lv2PluginClass::plugin_type_, get_plugin_type_enum_converter()), + MAP_REF(Lv2PluginClass, children), +}}; + +json_map::storage_type Lv2PluginUiPortGroup::jmap{{ + MAP_REF(Lv2PluginUiPortGroup, symbol), + MAP_REF(Lv2PluginUiPortGroup, name), +}}; + +JSON_MAP_BEGIN(Lv2PluginPreset) + JSON_MAP_REFERENCE(Lv2PluginPreset,presetUri) + JSON_MAP_REFERENCE(Lv2PluginPreset,name) +JSON_MAP_END() + diff --git a/src/Lv2Host.hpp b/src/Lv2Host.hpp new file mode 100644 index 0000000..dc1de35 --- /dev/null +++ b/src/Lv2Host.hpp @@ -0,0 +1,634 @@ +#pragma once + +#include +#include +#include "json.hpp" +#include "PluginType.hpp" +#include "PedalBoard.hpp" +#include +#include "MapFeature.hpp" +#include "LogFeature.hpp" +#include "OptionsFeature.hpp" +#include +#include + +#include "lv2/core/lv2.h" +#include "Units.hpp" + + + +namespace pipedal { + + +// forward declarations +class Lv2Effect; +class Lv2PedalBoard; +class Lv2Host; +class JackConfiguration; +class JackChannelSelection; + +#define LV2_PROPERTY_GETSET(name) \ + const decltype(name##_) & name() const { return name##_; }; \ + decltype(name##_) & name() { return name##_; }; \ + void name(const decltype(name##_) &value) { name##_ = value; }; + + +#define LV2_PROPERTY_GETSET_SCALAR(name) \ + decltype(name##_) name() const { return name##_;}; \ + void name(decltype(name##_) value) { name##_ = value; }; + + + + + +class Lv2PluginPreset { +public: + Lv2PluginPreset(const std::string &presetUri, const std::string&name) + : presetUri_(presetUri), + name_(name) + { + + } + Lv2PluginPreset() { } + + std::string presetUri_; + std::string name_; + + DECLARE_JSON_MAP(Lv2PluginPreset); +}; + + +class Lv2PluginClass { +public: + friend class Lv2Host; +private: + Lv2PluginClass* parent_; // NOT SERIALIZED! + std::string parent_uri_; + std::string display_name_; + std::string uri_; + PluginType plugin_type_; + std::vector> children_; + + + friend class ::pipedal::Lv2Host; + // hide copy constructor. + Lv2PluginClass(const Lv2PluginClass &other) + { + + } + void set_parent(std::shared_ptr &parent) + { + this->parent_ = parent.get(); + } + void add_child(std::shared_ptr &child) { + children_.push_back(child); + } +public: + Lv2PluginClass( + const char*display_name, const char*uri, const char*parent_uri) + : parent_uri_(parent_uri) + , display_name_(display_name) + , uri_(uri) + , plugin_type_(uri_to_plugin_type(uri)) + { + + } + Lv2PluginClass() { } + LV2_PROPERTY_GETSET(uri) + LV2_PROPERTY_GETSET(display_name) + LV2_PROPERTY_GETSET(parent_uri) + + const Lv2PluginClass *parent() { return parent_;} + + bool operator==(const Lv2PluginClass &other) + { + return uri_ == other.uri_; + } + bool is_a(const std::string& classUri) const; + + static json_map::storage_type jmap; + +}; +class Lv2PluginClasses { +private: + std::vector classes_; +public: + Lv2PluginClasses() + { + + } + Lv2PluginClasses(std::vector classes) + :classes_(classes) + { + + } + const std::vector & classes() const + { + return classes_; + } + bool is_a(Lv2Host*lv2Plugins,const char*classUri) const; + + static json_map::storage_type jmap; + +}; + + +class Lv2ScalePoint { +private: + float value_; + std::string label_; +public: + Lv2ScalePoint() { } + Lv2ScalePoint(float value, std::string label) + : value_(value) + , label_(label) + { + + } + + LV2_PROPERTY_GETSET_SCALAR(value); + LV2_PROPERTY_GETSET(label); + + static json_map::storage_type jmap; +}; + + +enum class Lv2BufferType { + None, + Event, + Sequence, + Unknown +}; + +class Lv2PortInfo { +private: + friend class Lv2PluginInfo; + Lv2PortInfo(Lv2Host*lv2Host,const LilvPlugin*pPlugin,const LilvPort *pPort); + + uint32_t index_; + std::string symbol_; + std::string name_; + float min_value_, max_value_, default_value_; + Lv2PluginClasses classes_; + std::vector scale_points_; + bool is_input_ = false; + bool is_output_ = false; + + bool is_control_port_ = false; + bool is_audio_port_ = false; + bool is_atom_port_ = false; + bool is_cv_port_ = false; + + bool is_valid_ = false; + bool supports_midi_ = false; + bool is_logarithmic_ = false; + int display_priority_ = -1; + int range_steps_ = 0; + bool trigger_; + bool integer_property_; + bool enumeration_property_; + bool toggled_property_; + bool not_on_gui_; + std::string buffer_type_; + std::string port_group_; + + std::string designation_; + Units units_ = Units::none; +public: + bool IsSwitch() const { + return min_value_ == 0 && max_value_ == 1 + && (integer_property_ || toggled_property_ || enumeration_property_); + } + float rangeToValue(float range) const + { + float value; + if (is_logarithmic_) + { + value = std::pow(max_value_/min_value_,range)*min_value_; + } else { + value = (max_value_-min_value_)*range+min_value_; + } + if (integer_property_ || enumeration_property_) + { + value = std::round(value); + } else if (range_steps_ >= 2) + { + value = std::round(value*(range_steps_-1))/(range_steps_-1); + } + if (toggled_property_) + { + value = value == 0 ? 0: max_value_; + } + if (value > max_value_) value = max_value_; + if (value < min_value_) value = min_value_; + return value; + } + LV2_PROPERTY_GETSET(symbol); + LV2_PROPERTY_GETSET_SCALAR(index); + LV2_PROPERTY_GETSET(name); + LV2_PROPERTY_GETSET(classes); + LV2_PROPERTY_GETSET(scale_points); + LV2_PROPERTY_GETSET_SCALAR(min_value); + LV2_PROPERTY_GETSET_SCALAR(max_value); + LV2_PROPERTY_GETSET_SCALAR(default_value); + + LV2_PROPERTY_GETSET_SCALAR(is_input); + LV2_PROPERTY_GETSET_SCALAR(is_output); + LV2_PROPERTY_GETSET_SCALAR(is_control_port); + LV2_PROPERTY_GETSET_SCALAR(is_audio_port); + LV2_PROPERTY_GETSET_SCALAR(is_atom_port); + LV2_PROPERTY_GETSET_SCALAR(is_cv_port); + LV2_PROPERTY_GETSET_SCALAR(is_valid); + LV2_PROPERTY_GETSET_SCALAR(supports_midi); + LV2_PROPERTY_GETSET_SCALAR(is_logarithmic); + LV2_PROPERTY_GETSET_SCALAR(display_priority); + LV2_PROPERTY_GETSET_SCALAR(range_steps); + LV2_PROPERTY_GETSET_SCALAR(trigger); + LV2_PROPERTY_GETSET_SCALAR(integer_property); + LV2_PROPERTY_GETSET_SCALAR(enumeration_property); + LV2_PROPERTY_GETSET_SCALAR(toggled_property); + LV2_PROPERTY_GETSET_SCALAR(not_on_gui); + LV2_PROPERTY_GETSET(port_group); + LV2_PROPERTY_GETSET_SCALAR(units); + + LV2_PROPERTY_GETSET(buffer_type); + + Lv2BufferType GetBufferType() { + if (buffer_type_ == "") return Lv2BufferType::None; + if (buffer_type_ == LV2_ATOM__Sequence) return Lv2BufferType::Sequence; + return Lv2BufferType::Unknown; + } + +public: + Lv2PortInfo() { } + ~Lv2PortInfo() = default; + bool is_a(Lv2Host*lv2Plugins,const char*classUri); + + static json_map::storage_type jmap; + +}; + +class Lv2PortGroup { +private: + std::string uri_; + std::string symbol_; + std::string name_; + +public: + LV2_PROPERTY_GETSET(uri); + LV2_PROPERTY_GETSET(symbol); + LV2_PROPERTY_GETSET(name); + + Lv2PortGroup() { } + Lv2PortGroup(Lv2Host*lv2Host,const std::string &groupUri); + + static json_map::storage_type jmap; +}; + +class Lv2PluginInfo { +private: + friend class Lv2Host; +public: + Lv2PluginInfo(Lv2Host*lv2Host,const LilvPlugin*); + Lv2PluginInfo() { } +private: + std::string uri_; + std::string name_; + std::string plugin_class_; + std::vector supported_features_; + std::vector required_features_; + std::vector optional_features_; + std::vector extensions_; + + std::string author_name_; + std::string author_homepage_; + + std::string comment_; + std::vector > ports_; + std::vector > port_groups_; + bool is_valid_ = false; + + bool IsSupportedFeature(const std::string &feature) const; + +public: + LV2_PROPERTY_GETSET(uri) + LV2_PROPERTY_GETSET(name) + LV2_PROPERTY_GETSET(plugin_class) + LV2_PROPERTY_GETSET(supported_features) + LV2_PROPERTY_GETSET(required_features) + LV2_PROPERTY_GETSET(optional_features) + LV2_PROPERTY_GETSET(author_name) + LV2_PROPERTY_GETSET(author_homepage) + LV2_PROPERTY_GETSET(comment) + LV2_PROPERTY_GETSET(extensions) + LV2_PROPERTY_GETSET(ports) + LV2_PROPERTY_GETSET(is_valid) + LV2_PROPERTY_GETSET(port_groups) + + const Lv2PortInfo& getPort(const std::string&symbol) + { + for (size_t i = 0; i < ports_.size(); ++i) + { + if (ports_[i]->symbol() == symbol) + { + return *(ports_[i].get()); + } + } + throw PiPedalArgumentException("Port not found."); + } + bool hasExtension(const std::string&uri) + { + for (int i = 0; i < extensions_.size(); ++i) + { + if (extensions_[i] == uri) return true; + } + return false; + } + bool hasCvPorts() const { + for (size_t i = 0; i < ports_.size(); ++i) + { + if (ports_[i]->is_cv_port()) + { + return true; + } + } + return false; + } + + +public: + + virtual ~Lv2PluginInfo(); + + static json_map::storage_type jmap; + +}; + + +class Lv2PluginUiControlPort { +public: + Lv2PluginUiControlPort() { + } + Lv2PluginUiControlPort(const Lv2PluginInfo *pPlugin,const Lv2PortInfo*pPort) + : symbol_(pPort->symbol()) + , index_(pPort->index()) + , name_(pPort->name()) + , min_value_(pPort->min_value()) + , max_value_(pPort->max_value()) + , default_value_(pPort->default_value()) + , range_steps_(pPort->range_steps()) + , display_priority_(pPort->display_priority()) + , is_logarithmic_(pPort->is_logarithmic()) + , integer_property_(pPort->integer_property()) + , enumeration_property_(pPort->enumeration_property()) + , toggled_property_(pPort->toggled_property()) + , not_on_gui_(pPort->not_on_gui()) + , scale_points_(pPort->scale_points()) + , units_(pPort->units()) + { + // Use symbols to index port groups, instead of uris. + // symbols are guaranteed to be unique. + auto &portGroup = pPort->port_group(); + for (int i = 0; i < pPlugin->port_groups().size(); ++i) + { + + auto &p = pPlugin->port_groups()[i]; + if (p->uri() == portGroup) + { + this->port_group_ = p->symbol(); + break; + } + + + } + } +private: + std::string symbol_; + int index_; + std::string name_; + float min_value_ = 0, max_value_ = 1,default_value_ = 0; + int range_steps_ = 0; + int display_priority_ = -1; + bool is_logarithmic_ = false; + bool integer_property_ = false; + bool enumeration_property_ = false; + bool toggled_property_ = false; + bool not_on_gui_ = false; + std::vector scale_points_; + std::string port_group_; + Units units_ = Units::none; +public: + LV2_PROPERTY_GETSET(symbol); + LV2_PROPERTY_GETSET_SCALAR(index); + LV2_PROPERTY_GETSET(name); + LV2_PROPERTY_GETSET_SCALAR(min_value); + LV2_PROPERTY_GETSET_SCALAR(max_value); + LV2_PROPERTY_GETSET_SCALAR(default_value); + LV2_PROPERTY_GETSET_SCALAR(range_steps); + LV2_PROPERTY_GETSET_SCALAR(display_priority); + LV2_PROPERTY_GETSET_SCALAR(is_logarithmic); + LV2_PROPERTY_GETSET_SCALAR(integer_property); + LV2_PROPERTY_GETSET_SCALAR(enumeration_property); + LV2_PROPERTY_GETSET_SCALAR(toggled_property); + LV2_PROPERTY_GETSET_SCALAR(not_on_gui); + LV2_PROPERTY_GETSET(scale_points); + LV2_PROPERTY_GETSET(units); + +public: + static json_map::storage_type jmap; + +}; + +class Lv2PluginUiPortGroup { +private: + std::string symbol_; + std::string name_; +public: + Lv2PluginUiPortGroup() { } + Lv2PluginUiPortGroup(Lv2PortGroup *pPortGroup) + : symbol_(pPortGroup->symbol()) + , name_(pPortGroup->name()) + { + } +public: + static json_map::storage_type jmap; + +}; + +class Lv2PluginUiInfo { +public: + Lv2PluginUiInfo() { } + Lv2PluginUiInfo(Lv2Host *pPlugins,const Lv2PluginInfo *plugin); + +private: + std::string uri_; + std::string name_; + std::string author_name_; + std::string author_homepage_; + PluginType plugin_type_; + std::string plugin_display_type_; + int audio_inputs_ = 0; + int audio_outputs_ = 0; + int has_midi_input_ = false; + int has_midi_output_ = false; + std::string description_; + + std::vector controls_; + std::vector port_groups_; + +public: + LV2_PROPERTY_GETSET(uri) + LV2_PROPERTY_GETSET(name) + LV2_PROPERTY_GETSET(author_name) + LV2_PROPERTY_GETSET(author_homepage) + LV2_PROPERTY_GETSET_SCALAR(plugin_type) + LV2_PROPERTY_GETSET(plugin_display_type) + LV2_PROPERTY_GETSET_SCALAR(audio_inputs) + LV2_PROPERTY_GETSET_SCALAR(audio_outputs) + LV2_PROPERTY_GETSET_SCALAR(has_midi_input) + LV2_PROPERTY_GETSET_SCALAR(has_midi_output) + LV2_PROPERTY_GETSET_SCALAR(description) + LV2_PROPERTY_GETSET(port_groups) + + + static json_map::storage_type jmap; + +}; + +class IHost { +public: + virtual LilvWorld*getWorld() = 0; + virtual LV2_URID_Map* GetLv2UridMap() = 0; + virtual LV2_URID GetLv2Urid(const char*uri) = 0; + virtual std::string Lv2UriudToString(LV2_URID urid) = 0; + + virtual LV2_Feature*const*GetLv2Features() const = 0; + virtual double GetSampleRate() const = 0; + virtual void SetMaxAudioBufferSize(size_t size) = 0; + virtual size_t GetMaxAudioBufferSize() const = 0; + virtual size_t GetAtomBufferSize() const = 0; + + virtual bool HasMidiInputChannel() const = 0; + virtual int GetNumberOfInputAudioChannels() const = 0; + virtual int GetNumberOfOutputAudioChannels() const = 0; + virtual std::shared_ptr GetPluginInfo(const std::string&uri) const = 0; + + + virtual Lv2Effect*CreateEffect(const PedalBoardItem &pedalBoard) = 0; +}; + +class Lv2Host: private IHost { +private: + size_t maxBufferSize = 1024; + size_t maxAtomBufferSize = 16*1024; + bool hasMidiInputChannel; + int numberOfAudioInputChannels = 2; + int numberOfAudioOutputChannels = 2; + double sampleRate = 0; + + LV2_Feature*const*lv2Features = nullptr; + MapFeature mapFeature; + LogFeature logFeature; + OptionsFeature optionsFeature; + + static void fn_LilvSetPortValueFunc(const char* port_symbol, + void* user_data, + const void* value, + uint32_t size, + uint32_t type); + + LilvWorld *pWorld; + void free_world(); + + + std::vector > plugins_; + std::vector ui_plugins_; + + std::map > classesMap; + + friend class Lv2PluginInfo; + friend class Lv2PortInfo; + friend class Lv2PortGroup; + + std::shared_ptr GetPluginClass(const LilvPluginClass*pClass); + std::shared_ptr MakePluginClass(const LilvPluginClass*pClass); + Lv2PluginClasses GetPluginPortClass(const LilvPlugin*lilvPlugin,const LilvPort *lilvPort); + + bool classesLoaded = false; + +private: + // IHost implementation + virtual LilvWorld*getWorld() { + return pWorld; + } + virtual void SetMaxAudioBufferSize(size_t size) { maxBufferSize = size; } + virtual size_t GetMaxAudioBufferSize() const { return maxBufferSize; } + virtual size_t GetAtomBufferSize() const { return maxAtomBufferSize; } + virtual bool HasMidiInputChannel() const { return hasMidiInputChannel;} + virtual int GetNumberOfInputAudioChannels() const { return numberOfAudioInputChannels; } + virtual int GetNumberOfOutputAudioChannels() const { return numberOfAudioOutputChannels;} + virtual LV2_Feature*const* GetLv2Features() const { return this->lv2Features; } + virtual LV2_URID_Map* GetLv2UridMap() { + return this->mapFeature.GetMap(); + } + + virtual Lv2Effect*CreateEffect(const PedalBoardItem &pedalBoardItem); + void LoadPluginClassesFromLilv(); + void AddJsonClassesToMap(std::shared_ptr pluginClass); + +public: + Lv2Host(); + virtual ~Lv2Host(); + + IHost* asIHost() { return this;} + + virtual Lv2PedalBoard * CreateLv2PedalBoard(const PedalBoard& pedalBoard); + + void setSampleRate(double sampleRate) + { + this->sampleRate = sampleRate; + } + double GetSampleRate() const { + return sampleRate; + } + + class Urids; + + Urids *urids; + + void OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings); + + std::shared_ptr GetPluginClass(const std::string&uri) const; + bool is_a(const std::string&class_, const std::string & target_class); + + std::shared_ptr GetLv2PluginClass() const; + + std::vector > GetPlugins() const { return plugins_; } + const std::vector &GetUiPlugins() const { return ui_plugins_; } + + virtual std::shared_ptr GetPluginInfo(const std::string&uri) const; + + + static constexpr const char * DEFAULT_LV2_PATH="/usr/lib/lv2"; + + + void LoadPluginClassesFromJson(std::filesystem::path jsonFile); + void Load(const char*lv2Path = Lv2Host::DEFAULT_LV2_PATH); + + virtual LV2_URID GetLv2Urid(const char*uri) { + return this->mapFeature.GetUrid(uri); + } + virtual std::string Lv2UriudToString(LV2_URID urid) { + return this->mapFeature.UridToString(urid); + } + + std::vector GetPluginPresets(const std::string &pluginUri); + std::vector LoadPluginPreset(PedalBoardItem*pedalBoardItem, const std::string&presetUri); + + + +}; + +#undef LV2_PROPERTY_GETSET + +} // namespace pipedal. \ No newline at end of file diff --git a/src/Lv2Log.cpp b/src/Lv2Log.cpp new file mode 100644 index 0000000..104c22e --- /dev/null +++ b/src/Lv2Log.cpp @@ -0,0 +1,95 @@ +#include "pch.h" +#include "Lv2Log.hpp" +#include +#include +#include + +using namespace pipedal; + +#include + + + + +static auto timeZero = std::chrono::system_clock::now(); + +std::string timeTag() +{ + using namespace std::chrono; + + auto t = std::chrono::system_clock::now()- timeZero; + + + auto hours_ = duration_cast(t).count() % 24; + auto minutes_ = duration_cast(t).count() % 60; + auto seconds_ = duration_cast(t).count() % 60; + auto milliseconds_ = duration_cast(t).count() % 1000; + + std::stringstream s; + + using namespace std; + s << setfill('0') << setw(2) << hours_ << ':' << setw(2) << minutes_ << ':' << setw(2) << seconds_ << "." << setw(3) << milliseconds_; + return s.str(); + +} +class StdErrLogger : public Lv2Logger +{ + std::mutex m; + + + public : virtual ~StdErrLogger() {} + + virtual void onError(const char* message) + { + std::lock_guard lock(m); + std::cerr << timeTag() << " ERR: " << message << std::endl; + } + virtual void onWarning(const char* message) + { + std::lock_guard lock(m); + std::cerr << timeTag() << " WRN: " << message << std::endl; + } + + virtual void onDebug(const char* message) + { + std::lock_guard lock(m); + std::cerr << timeTag() << " DBG: " << message << std::endl; + } + virtual void onInfo(const char* message) + { + std::lock_guard lock(m); + std::cerr << timeTag() << " INF: " << message << std::endl; + } +}; + +Lv2Logger *Lv2Log::logger_ = new StdErrLogger(); + +LogLevel Lv2Log::log_level_ = LogLevel::Debug; + +void Lv2Log::v_error(const char *format, va_list arglist) +{ + char buffer[512]; + vsnprintf(buffer,sizeof(buffer),format,arglist); + logger_->onError(buffer); +} +void Lv2Log::v_warning(const char *format, va_list arglist) +{ + char buffer[512]; + vsnprintf(buffer,sizeof(buffer),format,arglist); + logger_->onWarning(buffer); +} +void Lv2Log::v_debug(const char *format, va_list arglist) +{ + char buffer[512]; + vsnprintf(buffer,sizeof(buffer),format,arglist); + logger_->onDebug(buffer); +} +void Lv2Log::v_info(const char *format, va_list arglist) +{ + char buffer[512]; + vsnprintf(buffer,sizeof(buffer),format,arglist); + logger_->onInfo(buffer); + +} + + diff --git a/src/Lv2Log.hpp b/src/Lv2Log.hpp new file mode 100644 index 0000000..676b0ac --- /dev/null +++ b/src/Lv2Log.hpp @@ -0,0 +1,139 @@ +#pragma once +#include +#include + +namespace pipedal +{ + + class Lv2Logger + { + public: + virtual ~Lv2Logger() = default; + + virtual void onError(const char *message) = 0; + virtual void onWarning(const char *message) = 0; + virtual void onDebug(const char *message) = 0; + virtual void onInfo(const char *message) = 0; + }; + + enum class LogLevel + { + None = 0, + Error = 1, + Warning = 2, + Info = 3, + Debug = 4 + }; + + class Lv2Log + { + private: + static Lv2Logger *logger_; + static LogLevel log_level_; + + static void v_error(const char *format, va_list arglist); + static void v_warning(const char *format, va_list arglist); + static void v_debug(const char *format, va_list arglist); + static void v_info(const char *format, va_list arglist); + + public: + static void set_logger(Lv2Logger *logger) + { + Lv2Log::logger_ = logger; + } + static void log_level(LogLevel level) + { + Lv2Log::log_level_ = level; + } + static LogLevel log_level() + { + return Lv2Log::log_level_; + } + + // static void error(const char* message) { + // if (Lv2Log::log_level_ >= LogLevel::Error) + // { + // logger_->onError(message); + // } + // } + // static void warning(const char* message) { + // if (Lv2Log::log_level_ >= LogLevel::Warning) + // { + // logger_->onWarning(message); + // } + // } + // static void debug(const char* message) { + // if (Lv2Log::log_level_ >= LogLevel::Debug) + // { + // logger_->onDebug(message); + // } + // } + // static void info(const char* message) { + // if (Lv2Log::log_level_ >= LogLevel::Info) + // { + // logger_->onInfo(message); + // } + // } + + static void info(const char *format, ...) + { + if (Lv2Log::log_level_ >= LogLevel::Info) + { + va_list arglist; + va_start(arglist, format); + v_info(format, arglist); + va_end(arglist); + } + } + static void info(const std::string &str) + { + info("%s", str.c_str()); + } + + static void debug(const char *format, ...) + { + if (Lv2Log::log_level_ >= LogLevel::Debug) + { + va_list arglist; + va_start(arglist, format); + v_debug(format, arglist); + va_end(arglist); + } + } + static void debug(const std::string &str) + { + debug("%s", str.c_str()); + } + + static void warning(const char *format, ...) + { + if (Lv2Log::log_level_ >= LogLevel::Warning) + { + va_list arglist; + va_start(arglist, format); + v_warning(format, arglist); + va_end(arglist); + } + } + static void warning(const std::string &str) + { + warning("%s", str.c_str()); + } + + static void error(const char *format, ...) + { + if (Lv2Log::log_level_ >= LogLevel::Warning) + { + va_list arglist; + va_start(arglist, format); + v_error(format, arglist); + va_end(arglist); + } + } + static void error(const std::string &str) + { + error("%s", str.c_str()); + } + }; + +} // namespace pipedal \ No newline at end of file diff --git a/src/Lv2PedalBoard.cpp b/src/Lv2PedalBoard.cpp new file mode 100644 index 0000000..18eaf99 --- /dev/null +++ b/src/Lv2PedalBoard.cpp @@ -0,0 +1,584 @@ +#include "pch.h" +#include "Lv2PedalBoard.hpp" +#include "Lv2Effect.hpp" + +#include "SplitEffect.hpp" +#include "RingBufferReader.hpp" +#include "VuUpdate.hpp" +#include "JackHost.hpp" +#include "Lv2EventBufferWriter.hpp" + +using namespace pipedal; + +float *Lv2PedalBoard::CreateNewAudioBuffer() +{ + return bufferPool.AllocateBuffer(pHost->GetMaxAudioBufferSize()); +} + +std::vector Lv2PedalBoard::AllocateAudioBuffers(int nChannels) +{ + std::vector result; + for (int i = 0; i < nChannels; ++i) + { + result.push_back(bufferPool.AllocateBuffer(pHost->GetMaxAudioBufferSize())); + } + return result; +} + +int Lv2PedalBoard::GetControlIndex(long instanceId, const std::string &symbol) +{ + for (int i = 0; i < realtimeEffects.size(); ++i) + { + auto item = realtimeEffects[i]; + if (item->GetInstanceId() == instanceId) + { + return item->GetControlIndex(symbol); + } + } + return -1; +} +std::vector Lv2PedalBoard::PrepareItems( + const std::vector &items, + std::vector inputBuffers) +{ + for (int i = 0; i < items.size(); ++i) + { + auto &item = items[i]; + if (!item.isEmpty()) + { + IEffect *pEffect = nullptr; + if (item.isSplit()) + { + auto pSplit = new SplitEffect(item.instanceId(), pHost->GetSampleRate(), inputBuffers); + pEffect = pSplit; + + int topInputChannels = inputBuffers.size(); + int bottomInputChannels = inputBuffers.size(); + + std::vector topInputs = AllocateAudioBuffers(topInputChannels); + std::vector bottomInputs = AllocateAudioBuffers(bottomInputChannels); + + auto preMixAction = [pSplit](uint32_t frames) + { pSplit->PreMix(frames); }; + + this->processActions.push_back(preMixAction); + + std::vector topResult = PrepareItems(item.topChain(), topInputs); + std::vector bottomResult = PrepareItems(item.bottomChain(), bottomInputs); + + this->processActions.push_back( + [pSplit](uint32_t frames) + { pSplit->PostMix(frames); }); + + pSplit->SetChainBuffers(topInputs, bottomInputs, topResult, bottomResult); + + for (int i = 0; i < item.controlValues().size(); ++i) + { + auto &controlValue = item.controlValues()[i]; + int index = pSplit->GetControlIndex(controlValue.key()); + if (index != -1) + { + pSplit->SetControl(index, controlValue.value()); + } + } + } + else + { + + auto pLv2Effect = this->pHost->CreateEffect(item); + if (pLv2Effect) + { + pEffect = pLv2Effect; + + long instanceId = pEffect->GetInstanceId(); + + if (inputBuffers.size() == 1) + { + if (pLv2Effect->GetNumberOfInputAudioPorts() == 1) + { + pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]); + } + else + { + pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]); + pLv2Effect->SetAudioInputBuffer(1, inputBuffers[0]); + } + } + else + { + if (pLv2Effect->GetNumberOfInputAudioPorts() == 1) + { + pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]); + + auto inputBuffer = inputBuffers[0]; + } + else + { + pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]); + pLv2Effect->SetAudioInputBuffer(1, inputBuffers[1]); + + auto bufferL = inputBuffers[0]; + auto bufferR = inputBuffers[1]; + } + } + + this->processActions.push_back( + [pLv2Effect](uint32_t frames) + { + pLv2Effect->Run(frames); + }); + } + } + if (pEffect) + { + this->effects.push_back(std::shared_ptr(pEffect)); // for ownership. + this->realtimeEffects.push_back(pEffect); // because std::shared_ptr is not threadsafe. + + std::vector effectOutput; + +#ifdef RECYCLE_AUDIO_BUFFERS + // can't do this anymore if we're going to do pop-less bypbass. + if (pEffect->GetNumberOfOutputAudioPorts() == 1) + { + float *pLeft = inputBuffers[0]; + effectOutput.push_back(pLeft); + } + else + { + if (inputBuffers.size() == 1) + { + effectOutput.push_back(inputBuffers[0]); + effectOutput.push_back(CreateNewAudioBuffer()); + } + else + { + effectOutput.push_back(inputBuffers[0]); + effectOutput.push_back(inputBuffers[1]); + } + } +#else + if (pEffect->GetNumberOfOutputAudioPorts() == 1) + { + effectOutput.push_back(CreateNewAudioBuffer()); + } + else + { + effectOutput.push_back(CreateNewAudioBuffer()); + effectOutput.push_back(CreateNewAudioBuffer()); + } +#endif + for (size_t i = 0; i < effectOutput.size(); ++i) + { + pEffect->SetAudioOutputBuffer(i, effectOutput[i]); + } + inputBuffers = effectOutput; + } + } + } + return inputBuffers; +} + +void Lv2PedalBoard::Prepare(IHost *pHost, const PedalBoard &pedalBoard) +{ + this->pHost = pHost; + + for (int i = 0; i < pHost->GetNumberOfInputAudioChannels(); ++i) + { + this->pedalBoardInputBuffers.push_back(bufferPool.AllocateBuffer(pHost->GetMaxAudioBufferSize())); + } + + auto outputs = PrepareItems(pedalBoard.items(), this->pedalBoardInputBuffers); + int nOutputs = pHost->GetNumberOfOutputAudioChannels(); + if (nOutputs == 1) + { + this->pedalBoardOutputBuffers.push_back(outputs[0]); + } + else + { + if (outputs.size() == 1) + { + this->pedalBoardOutputBuffers.push_back(outputs[0]); + this->pedalBoardOutputBuffers.push_back(outputs[0]); + } + else + { + this->pedalBoardOutputBuffers.push_back(outputs[0]); + this->pedalBoardOutputBuffers.push_back(outputs[1]); + } + } + PrepareMidiMap(pedalBoard); +} + +void Lv2PedalBoard::PrepareMidiMap(const PedalBoardItem &pedalBoardItem) +{ + if (pedalBoardItem.midiBindings().size() != 0) + { + auto pluginInfo = pHost->GetPluginInfo(pedalBoardItem.uri()); + const Lv2PluginInfo *pPluginInfo; + if (pluginInfo == nullptr && pedalBoardItem.uri() == SPLIT_PEDALBOARD_ITEM_URI) + { + pPluginInfo = GetSplitterPluginInfo(); + } else { + pPluginInfo = pluginInfo.get(); + } + + int effectIndex = this->GetIndexOfInstanceId(pedalBoardItem.instanceId()); + + if (pluginInfo && effectIndex != -1) + { + for (size_t bindingIndex = 0; bindingIndex < pedalBoardItem.midiBindings().size(); ++bindingIndex) + { + auto &binding = pedalBoardItem.midiBindings()[bindingIndex]; + { + const Lv2PortInfo*pPortInfo; + int controlIndex; + if (binding.symbol() == "__bypass") + { + pPortInfo = GetBypassPortInfo(); + controlIndex = -1; + } else { + try { + pPortInfo = &pluginInfo->getPort(binding.symbol()); + controlIndex = this->GetControlIndex(pedalBoardItem.instanceId(), binding.symbol()); + } catch (const std::exception&ignored) + { + continue; + } + + + } + + MidiMapping mapping; + mapping.pluginInfo = pluginInfo; // for lifetime management. We're holding internal pointers to this. May save us in a disorderly shutdown. + mapping.pPortInfo = pPortInfo; + mapping.effectIndex = effectIndex; + mapping.controlIndex = controlIndex; + mapping.midiBinding = binding; + mapping.instanceId = pedalBoardItem.instanceId(); + if (pPortInfo->IsSwitch()) + { + mapping.mappingType = binding.switchControlType() == LATCH_CONTROL_TYPE ? MappingType::Latched : MappingType::Momentary; + } + else + { + mapping.mappingType = binding.linearControlType() == LATCH_CONTROL_TYPE ? MappingType::Linear : MappingType::Circular; + } + if (binding.bindingType() == BINDING_TYPE_NOTE) + { + mapping.key = 0x9000 | binding.note(); // i.e. midi note on. + } + else if (binding.bindingType() == BINDING_TYPE_CONTROL) + { + mapping.key = 0xB000 | binding.control(); // i.e. midi control + } + else + { + mapping.key = -1; + } + if (mapping.key != -1) + { + midiMappings.push_back(std::move(mapping)); + } + } + } + } + } + for (size_t i = 0; i < pedalBoardItem.topChain().size(); ++i) + { + PrepareMidiMap(pedalBoardItem.topChain()[i]); + } + for (size_t i = 0; i < pedalBoardItem.bottomChain().size(); ++i) + { + PrepareMidiMap(pedalBoardItem.bottomChain()[i]); + } +} +void Lv2PedalBoard::PrepareMidiMap(const PedalBoard &pedalBoard) +{ + for (size_t i = 0; i < pedalBoard.items().size(); ++i) + { + auto &item = pedalBoard.items()[i]; + PrepareMidiMap(item); + + auto pluginInfo = pHost->GetPluginInfo(item.uri()); + + if (pluginInfo) + { + for (size_t bindingIndex = 0; bindingIndex < item.midiBindings().size(); ++bindingIndex) + { + auto &binding = item.midiBindings()[i]; + { + } + } + } + std::sort(this->midiMappings.begin(), this->midiMappings.end(), + [](const MidiMapping &left, const MidiMapping &right) + { return left.key < right.key; }); + } +} +void Lv2PedalBoard::Activate() +{ + for (int i = 0; i < this->effects.size(); ++i) + { + this->realtimeEffects[i]->Activate(); + } +} +void Lv2PedalBoard::Deactivate() +{ + for (int i = 0; i < this->effects.size(); ++i) + { + this->realtimeEffects[i]->Deactivate(); + } +} + +static void Copy(float *input, float *output, uint32_t samples) +{ + for (uint32_t i = 0; i < samples; ++i) + { + output[i] = input[i]; + } +} +bool Lv2PedalBoard::Run(float **inputBuffers, float **outputBuffers, uint32_t samples) +{ + + for (int i = 0; i < this->pedalBoardInputBuffers.size(); ++i) + { + if (inputBuffers[i] == nullptr) + return false; + Copy(inputBuffers[i], this->pedalBoardInputBuffers[i], samples); + } + for (int i = 0; i < this->processActions.size(); ++i) + { + processActions[i](samples); + } + for (int i = 0; i < this->pedalBoardOutputBuffers.size(); ++i) + { + if (outputBuffers[i] == nullptr) + return false; + Copy(this->pedalBoardOutputBuffers[i], outputBuffers[i], samples); + } + return true; +} + +float Lv2PedalBoard::GetControlOutputValue(int effectIndex, int portIndex) +{ + auto effect = realtimeEffects[effectIndex]; + return effect->GetOutputControlValue(portIndex); +} + +void Lv2PedalBoard::SetControlValue(int effectIndex, int index, float value) +{ + auto effect = realtimeEffects[effectIndex]; + effect->SetControl(index, value); +} +void Lv2PedalBoard::SetBypass(int effectIndex, bool enabled) +{ + auto effect = realtimeEffects[effectIndex]; + effect->SetBypass(enabled); +} + +void Lv2PedalBoard::ComputeVus(RealtimeVuBuffers *vuConfiguration, uint32_t samples) +{ + for (size_t i = 0; i < vuConfiguration->enabledIndexes.size(); ++i) + { + int index = vuConfiguration->enabledIndexes[i]; + VuUpdate *pUpdate = &vuConfiguration->vuUpdateWorkingData[i]; + + auto effect = this->realtimeEffects[index]; + + if (effect->GetNumberOfInputAudioPorts() == 1) + { + pUpdate->AccumulateInputs(effect->GetAudioInputBuffer(0), samples); + } + else + { + pUpdate->AccumulateInputs( + effect->GetAudioInputBuffer(0), + effect->GetAudioInputBuffer(1), samples); + } + if (effect->GetNumberOfOutputAudioPorts() == 1) + { + pUpdate->AccumulateOutputs(effect->GetAudioOutputBuffer(0), samples); + } + else + { + pUpdate->AccumulateOutputs( + effect->GetAudioOutputBuffer(0), + effect->GetAudioOutputBuffer(1), + samples); + } + } +} + +void Lv2PedalBoard::ResetAtomBuffers() +{ + for (size_t i = 0; i < this->effects.size(); ++i) + { + auto effect = this->effects[i]; + effect->ResetAtomBuffers(); + } +} + +void Lv2PedalBoard::ProcessParameterRequests(RealtimeParameterRequest *pParameterRequests) +{ + while (pParameterRequests != nullptr) + { + IEffect *pEffect = this->GetEffect(pParameterRequests->instanceId); + if (pEffect == nullptr) + { + pParameterRequests->errorMessage = "No such effect."; + } + else + { + pEffect->RequestParameter(pParameterRequests->uridUri); + } + pParameterRequests = pParameterRequests->pNext; + } +} + +void Lv2PedalBoard::GatherParameterRequests(RealtimeParameterRequest *pParameterRequests) +{ + while (pParameterRequests != nullptr) + { + IEffect *effect = this->GetEffect(pParameterRequests->instanceId); + if (effect == nullptr) + { + pParameterRequests->errorMessage = "No such effect."; + } + else + { + effect->GatherParameter(pParameterRequests); + } + + pParameterRequests = pParameterRequests->pNext; + } +} + +void Lv2PedalBoard::OnMidiMessage(size_t size, uint8_t *message, + void *callbackHandle, + MidiCallbackFn *pfnCallback) + +{ + if (midiMappings.size() == 0) + return; + + if (size < 2) + return; + uint8_t cmd = message[0]; + uint8_t channel = cmd & 0x0F; + cmd &= 0xF0; + + uint8_t value; + uint8_t index; + if (cmd == 0x80) // note off. + { + index = message[1]; + cmd = 0x90; + index = message[1]; + value = 0; + } + else if (cmd == 0x90) // note on. + { + if (size < 3) + return; + index = message[1]; + value = 127; + } + else if (cmd == 0xB0) // midi control. + { + if (size < 3) + return; + index = message[1]; + value = message[2] & 0x7F; + } + int searchKey = (cmd << 8) | index; + int min = 0; + int max = midiMappings.size() - 1; + while (max > min) + { + int mid = (min + max) / 2; + if (midiMappings[mid].key < searchKey) + { + min = mid + 1; + } + else if (midiMappings[mid].key > searchKey) + { + max = mid - 1; + } + else + { + if (mid == 0) + { + min = max = mid; + } + else + { + if (midiMappings[mid - 1].key == searchKey) + { + max = mid - 1; + } + else + { + min = max = mid; + } + } + } + } + if (midiMappings[min].key == searchKey) + { + float range = value / 127.0; + + for (int i = min; i < midiMappings.size(); ++i) + { + auto &mapping = midiMappings[i]; + if (mapping.key != searchKey) + break; + + if (mapping.midiBinding.channel() == -1 || mapping.midiBinding.channel() == channel) + { + switch (mapping.mappingType) + { + case MappingType::Circular: + case MappingType::Linear: + { + float thisRange = (mapping.midiBinding.maxValue() - mapping.midiBinding.minValue()) * range + mapping.midiBinding.minValue(); + float value = mapping.pPortInfo->rangeToValue(thisRange); + this->SetControlValue(mapping.effectIndex, mapping.controlIndex, value); + pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), value); + break; + } + case MappingType::Latched: + { + range = std::round(range); + + if (!mapping.hasLastValue) + { + mapping.lastValue = 0; + mapping.hasLastValue = true; + } + if (range != mapping.lastValue && range == 1) + { + IEffect *pEffect = this->realtimeEffects[mapping.effectIndex]; + float currentValue = pEffect->GetControlValue(mapping.controlIndex); + currentValue = currentValue == 0 ? 1 : 0; + pEffect->SetControl(mapping.controlIndex, currentValue); + pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), currentValue); + } + mapping.lastValue = range; + break; + } + case MappingType::Momentary: + { + IEffect *pEffect = this->realtimeEffects[mapping.effectIndex]; + float value = mapping.pPortInfo->rangeToValue(range); + if (pEffect->GetControlValue(mapping.controlIndex) != value) + { + this->SetControlValue(mapping.effectIndex, mapping.controlIndex, value); + pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), value); + } + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Lv2PedalBoard.hpp b/src/Lv2PedalBoard.hpp new file mode 100644 index 0000000..d52f98d --- /dev/null +++ b/src/Lv2PedalBoard.hpp @@ -0,0 +1,125 @@ +#pragma once +#include "PedalBoard.hpp" +#include "Lv2Host.hpp" +#include "Lv2Effect.hpp" +#include "BufferPool.hpp" +#include +#include +#include + +namespace pipedal { + + + +class RealtimeVuBuffers; +class RealtimeParameterRequest; + +class Lv2PedalBoard { + IHost *pHost = nullptr; + + BufferPool bufferPool; + std::vector pedalBoardInputBuffers; + std::vector pedalBoardOutputBuffers; + + std::vector > effects; + std::vector realtimeEffects; // std::shared_ptr is not thread-safe!! + + using Action = std::function; + using ProcessAction = std::function; + + std::vector activateActions; + + std::vector processActions; + + std::vector deactivateActions; + + float *CreateNewAudioBuffer(); + + enum class MappingType { + Linear, + Circular, + Momentary, + Latched, + }; + class MidiMapping { + public: + std::shared_ptr pluginInfo; // lifecycle + const Lv2PortInfo *pPortInfo = nullptr; // owned by port. + int instanceId = -1; + int effectIndex = -1; + int controlIndex = -1; + int key; // key to the note or control. internal use only. + bool hasLastValue = false; + float lastValue = -1; + MappingType mappingType; + MidiBinding midiBinding; + }; + + std::vector midiMappings; + + + std::vector PrepareItems( + const std::vector & items, + std::vector inputBuffers + ); + + void PrepareMidiMap(const PedalBoard&pedalBoard); + void PrepareMidiMap(const PedalBoardItem&pedalBoardItem); + + std::vector AllocateAudioBuffers(int nChannels); + int CalculateChainInputs(const std::vector &inputBuffers, const std::vector &items); + void AppendParameterRequest(uint8_t*atomBuffer, LV2_URID uridParameter); +public: + Lv2PedalBoard() { } + ~Lv2PedalBoard() { } + + void Prepare(IHost *pHost,const PedalBoard&pedalBoard); + + int GetIndexOfInstanceId(long instanceId) { + for (int i = 0; i < this->realtimeEffects.size(); ++i) + { + if (this->realtimeEffects[i]->GetInstanceId() == instanceId) return i; + } + return -1; + } + IEffect*GetEffect(long instanceId) { + for (int i = 0; i < realtimeEffects.size(); ++i) { + if (realtimeEffects[i]->GetInstanceId() == instanceId) + { + return realtimeEffects[i]; + } + } + return nullptr; + } + void Activate(); + void Deactivate(); + bool Run(float**inputBuffers, float**outputBuffers,uint32_t samples); + + void ResetAtomBuffers(); + + + void ProcessParameterRequests(RealtimeParameterRequest *pParameterRequests); + void GatherParameterRequests(RealtimeParameterRequest *pParameterRequests); + + + std::vector &GetInputBuffers() { return this->pedalBoardInputBuffers;} + std::vector &GetoutputBuffers() { return this->pedalBoardOutputBuffers;} + + + + int GetControlIndex(long instanceId,const std::string&symbol); + void SetControlValue(int effectIndex, int portIndex, float value); + void SetBypass(int effectIndex,bool enabled); + + void ComputeVus(RealtimeVuBuffers *vuConfiguration, uint32_t samples); + + float GetControlOutputValue(int effectIndex, int portIndex); + + typedef void (MidiCallbackFn) (void* data,uint64_t intanceId, int controlIndex, float value); + void OnMidiMessage(size_t size, uint8_t*data, + void *callbackHandle, + MidiCallbackFn*pfnCallback); + +}; + +} // namespace \ No newline at end of file diff --git a/src/Lv2SystemdLogger.cpp b/src/Lv2SystemdLogger.cpp new file mode 100644 index 0000000..ef7f7d9 --- /dev/null +++ b/src/Lv2SystemdLogger.cpp @@ -0,0 +1,35 @@ +#include "pch.h" +#include "Lv2SystemdLogger.hpp" +#include + +using namespace pipedal; + +class Lv2SystemdLogger: public Lv2Logger { +public: + virtual ~Lv2SystemdLogger() { } + virtual void onError(const char* message) + { + sd_journal_print(LOG_ERR,"%s",message); + } + virtual void onWarning(const char* message) + { + sd_journal_print(LOG_WARNING,"%s",message); + + } + virtual void onDebug(const char* message) + { + sd_journal_print(LOG_DEBUG,"%s",message); + + } + virtual void onInfo(const char* message) + { + sd_journal_print(LOG_INFO,"%s",message); + } + +}; + + +Lv2Logger *pipedal::MakeLv2SystemdLogger() +{ + return new Lv2SystemdLogger(); +} diff --git a/src/Lv2SystemdLogger.hpp b/src/Lv2SystemdLogger.hpp new file mode 100644 index 0000000..cc86cf4 --- /dev/null +++ b/src/Lv2SystemdLogger.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "Lv2Log.hpp" + +namespace pipedal { + + Lv2Logger *MakeLv2SystemdLogger(); +} // namespace diff --git a/src/MapFeature.cpp b/src/MapFeature.cpp new file mode 100644 index 0000000..bcd1e47 --- /dev/null +++ b/src/MapFeature.cpp @@ -0,0 +1,63 @@ +#include "MapFeature.hpp" +#include + +using namespace pipedal; + +static LV2_URID mapFn(LV2_URID_Map_Handle handle, const char* uri) +{ + MapFeature* feature = (MapFeature*)(void*)handle; + return feature->GetUrid(uri); +} +static const char* unmapFn(LV2_URID_Map_Handle handle, LV2_URID urid) +{ + MapFeature* feature = (MapFeature*)(void*)handle; + return feature->UridToString(urid); +} + +MapFeature::MapFeature() +{ + mapFeature.URI = LV2_URID__map; + mapFeature.data = ↦ + map.handle = (void*)this; + map.map = &mapFn; + + unmapFeature.URI = LV2_URID__unmap; + unmapFeature.data = &unmap; + unmap.handle = (void*)this; + unmap.unmap = &unmapFn; +} + +MapFeature::~MapFeature() +{ + for (auto i = stdUnmap.begin(); i != stdUnmap.end(); ++i) + { + delete i->second; + } +} + +LV2_URID MapFeature::GetUrid(const char* uri) +{ + + std::lock_guard guard(mapMutex); + + LV2_URID result = stdMap[uri]; + if (result == 0) + { + stdMap[uri] = ++nextAtom; + result = nextAtom; + std::string *stringRef = new std::string(uri); + stdUnmap[result] = stringRef; + } + return result; +} + +const char*MapFeature::UridToString(LV2_URID urid) +{ + std::lock_guard guard(mapMutex); + + std::string*pResult = stdUnmap[urid]; + if (pResult == nullptr) return nullptr; + + return pResult->c_str(); + +} diff --git a/src/MapFeature.hpp b/src/MapFeature.hpp new file mode 100644 index 0000000..b6c75fc --- /dev/null +++ b/src/MapFeature.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "lv2/core/lv2.h" + +#include "lv2/atom/atom.h" +#include "lv2/atom/util.h" +#include "lv2/core/lv2.h" +#include "lv2/log/log.h" +#include "lv2/log/logger.h" +#include "lv2/midi/midi.h" +#include "lv2/urid/urid.h" +#include "lv2/atom/atom.h" +#include +#include +#include + + +namespace pipedal { + class MapFeature { + + private: + LV2_URID nextAtom = 0; + LV2_Feature mapFeature; + LV2_Feature unmapFeature; + LV2_URID_Map map; + LV2_URID_Unmap unmap; + std::map stdMap; + std::map stdUnmap; + std::mutex mapMutex; + + + public: + MapFeature(); + ~MapFeature(); + public: + const LV2_Feature* GetMapFeature() + { + return &mapFeature; + } + const LV2_Feature* GetUnmapFeature() + { + return &unmapFeature; + } + LV2_URID GetUrid(const char* uri); + + const char*UridToString(LV2_URID urid); + + const LV2_URID_Map *GetMap() const { return ↦} + LV2_URID_Map *GetMap() { return ↦} + + }; +} \ No newline at end of file diff --git a/src/MidiBinding.cpp b/src/MidiBinding.cpp new file mode 100644 index 0000000..e91cfdd --- /dev/null +++ b/src/MidiBinding.cpp @@ -0,0 +1,19 @@ +#include "pch.h" +#include "MidiBinding.hpp" + + +using namespace pipedal; + +JSON_MAP_BEGIN(MidiBinding) + JSON_MAP_REFERENCE(MidiBinding,channel) + JSON_MAP_REFERENCE(MidiBinding,symbol) + JSON_MAP_REFERENCE(MidiBinding,bindingType) + JSON_MAP_REFERENCE(MidiBinding,note) + JSON_MAP_REFERENCE(MidiBinding,control) + JSON_MAP_REFERENCE(MidiBinding,minValue) + JSON_MAP_REFERENCE(MidiBinding,maxValue) + JSON_MAP_REFERENCE(MidiBinding,rotaryScale) + JSON_MAP_REFERENCE(MidiBinding,linearControlType) + JSON_MAP_REFERENCE(MidiBinding,switchControlType) +JSON_MAP_END() + diff --git a/src/MidiBinding.hpp b/src/MidiBinding.hpp new file mode 100644 index 0000000..6eb44e0 --- /dev/null +++ b/src/MidiBinding.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include "json.hpp" + + +namespace pipedal { + + +#define GETTER_SETTER_REF(name) \ + const decltype(name##_)& name() const { return name##_;} \ + void name(const decltype(name##_) &value) { name##_ = value; } + +#define GETTER_SETTER_VEC(name) \ + decltype(name##_)& name() { return name##_;} \ + const decltype(name##_)& name() const { return name##_;} + + + +#define GETTER_SETTER(name) \ + decltype(name##_) name() const { return name##_;} \ + void name(decltype(name##_) value) { name##_ = value; } + + + + const int BINDING_TYPE_NONE = 0; + const int BINDING_TYPE_NOTE = 1; + const int BINDING_TYPE_CONTROL = 2; + + const int LINEAR_CONTROL_TYPE = 0; + const int CIRCULAR_CONTROL_TYPE = 1; + + const int LATCH_CONTROL_TYPE = 0; + const int MOMENTARY_CONTROL_TYPE = 1; + + + +class MidiBinding { +public: +private: + std::string symbol_; + int channel_ = -1; + int bindingType_; + int note_ = 12*4+24; + int control_ = 1; + float minValue_ = 0; + float maxValue_ = 1; + float rotaryScale_ = 1; + int linearControlType_ = 0; + int switchControlType_ = 0; +public: + GETTER_SETTER(channel); + GETTER_SETTER_REF(symbol); + GETTER_SETTER(bindingType); + GETTER_SETTER(note); + GETTER_SETTER(control); + GETTER_SETTER(minValue); + GETTER_SETTER(maxValue); + GETTER_SETTER(rotaryScale); + GETTER_SETTER(linearControlType); + GETTER_SETTER(switchControlType); + + DECLARE_JSON_MAP(MidiBinding); + +}; + +#undef GETTER_SETTER_REF +#undef GETTER_SETTER_VEC +#undef GETTER_SETTER + + + +} // namespace \ No newline at end of file diff --git a/src/OptionsFeature.cpp b/src/OptionsFeature.cpp new file mode 100644 index 0000000..167d4cb --- /dev/null +++ b/src/OptionsFeature.cpp @@ -0,0 +1,67 @@ +#include "pch.h" +#include "OptionsFeature.hpp" + +#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h" +using namespace pipedal; + +OptionsFeature::OptionsFeature() +{ + feature.URI = LV2_OPTIONS__options; + feature.data = options; + +} + +OptionsFeature::~OptionsFeature() +{ + +} +void OptionsFeature::Prepare(MapFeature&map,double sampleRate, int32_t blockLength, int32_t atomBufferBlockLength) +{ + this->sampleRate = (float)sampleRate; + this->blockLength = blockLength; + this->atomBufferBlockLength = atomBufferBlockLength; + + + options[0].context = LV2_OPTIONS_INSTANCE; + options[0].subject = 0; + options[0].key = map.GetUrid(LV2_PARAMETERS__sampleRate); + options[0].size = sizeof(float); + options[0].type = map.GetUrid(LV2_ATOM__Float); + options[0].value = &(this->sampleRate); + + options[1].context = LV2_OPTIONS_INSTANCE; + options[1].subject = 0; + options[1].key = map.GetUrid(LV2_BUF_SIZE__minBlockLength); + options[1].size = sizeof(int32_t); + options[1].type = map.GetUrid(LV2_ATOM__Int); + options[1].value = &(this->blockLength); + + options[2].context = LV2_OPTIONS_INSTANCE; + options[2].subject = 0; + options[2].key = map.GetUrid(LV2_BUF_SIZE__maxBlockLength); + options[2].size = sizeof(int32_t); + options[2].type = map.GetUrid(LV2_ATOM__Int); + options[2].value = &(this->blockLength); + + options[3].context = LV2_OPTIONS_INSTANCE; + options[3].subject = 0; + options[3].key = map.GetUrid(LV2_BUF_SIZE__nominalBlockLength); + options[3].size = sizeof(int32_t); + options[3].type = map.GetUrid(LV2_ATOM__Int); + options[3].value = &(this->blockLength); + + options[4].context = LV2_OPTIONS_INSTANCE; + options[4].subject = 0; + options[4].key = map.GetUrid(LV2_BUF_SIZE__sequenceSize); + options[4].size = sizeof(int32_t); + options[4].type = map.GetUrid(LV2_ATOM__Int); + options[4].value = &(this->atomBufferBlockLength);; + + options[5].context = LV2_OPTIONS_INSTANCE; + options[5].subject = 0; + options[5].key = 0; + options[5].size = 0; + options[5].type = 0; + options[5].value = NULL; + +} \ No newline at end of file diff --git a/src/OptionsFeature.hpp b/src/OptionsFeature.hpp new file mode 100644 index 0000000..33cfff2 --- /dev/null +++ b/src/OptionsFeature.hpp @@ -0,0 +1,34 @@ +#pragma once + + +#include "MapFeature.hpp" +#include "lv2/lv2plug.in/ns/ext/options/options.h" + +namespace pipedal { + + + class OptionsFeature { + + private: + float sampleRate; + int32_t blockLength; + int32_t atomBufferBlockLength; + + LV2_Feature feature; + LV2_Options_Option options[6]; + + public: + OptionsFeature(); + void Prepare(MapFeature&map, + double sampleRate, + int32_t blockLength, + int32_t atomBufferBlockLength); + ~OptionsFeature(); + public: + const LV2_Feature* GetFeature() + { + return &feature; + } + }; + +} \ No newline at end of file diff --git a/src/PedalBoard.cpp b/src/PedalBoard.cpp new file mode 100644 index 0000000..3a3c31d --- /dev/null +++ b/src/PedalBoard.cpp @@ -0,0 +1,183 @@ +#include "pch.h" +#include "PedalBoard.hpp" + + +using namespace pipedal; + + +static const PedalBoardItem* GetItem_(const std::vector&items,long pedalBoardItemId) +{ + for (size_t i = 0; i < items.size(); ++i) + { + auto &item = items[i]; + if (items[i].instanceId() == pedalBoardItemId) + { + return &(items[i]); + } + if (item.isSplit()) + { + const PedalBoardItem* t = GetItem_(item.topChain(),pedalBoardItemId); + if (t != nullptr) return t; + t = GetItem_(item.bottomChain(),pedalBoardItemId); + if (t != nullptr) return t; + } + } + return nullptr; +} + +const PedalBoardItem*PedalBoard::GetItem(long pedalItemId) const +{ + return GetItem_(this->items(),pedalItemId); +} +PedalBoardItem*PedalBoard::GetItem(long pedalItemId) + { + return const_cast(GetItem_(this->items(),pedalItemId)); + } + +ControlValue* PedalBoardItem::GetControlValue(const std::string&symbol) +{ + for (size_t i = 0; i < this->controlValues().size(); ++i) + { + if (this->controlValues()[i].key() == symbol) + { + return &(this->controlValues()[i]); + } + } + return nullptr; +} + +bool PedalBoard::SetItemEnabled(long pedalItemId, bool enabled) +{ + PedalBoardItem*item = GetItem(pedalItemId); + if (!item) return false; + if (item->isEnabled() != enabled) + { + item->isEnabled(enabled); + return true; + } + return false; + +} + + +bool PedalBoard::SetControlValue(long pedalItemId, const std::string &symbol, float value) +{ + PedalBoardItem*item = GetItem(pedalItemId); + if (!item) return false; + ControlValue*controlValue = item->GetControlValue(symbol); + if (controlValue == nullptr) return false; + if (controlValue->value() != value) + { + controlValue->value(value); + return true; + } + return false; +} + + +PedalBoardItem PedalBoard::MakeEmptyItem() +{ + long instanceId = NextInstanceId(); + + PedalBoardItem result; + result.instanceId(instanceId); + result.uri(EMPTY_PEDALBOARD_ITEM_URI); + result.pluginName(""); + result.isEnabled(true); + return result; +} + + +PedalBoardItem PedalBoard::MakeSplit() +{ + long instanceId = NextInstanceId(); + + PedalBoardItem result; + result.instanceId(instanceId); + result.uri(SPLIT_PEDALBOARD_ITEM_URI); + result.pluginName(""); + result.isEnabled(true); + + result.topChain().push_back(MakeEmptyItem()); + result.bottomChain().push_back(MakeEmptyItem()); + result.controlValues().push_back( + ControlValue(SPLIT_SPLITTYPE_KEY,0)); + result.controlValues().push_back( + ControlValue(SPLIT_SELECT_KEY,0)); + result.controlValues().push_back( + ControlValue(SPLIT_MIX_KEY,0)); + result.controlValues().push_back( + ControlValue(SPLIT_PANL_KEY,0)); + result.controlValues().push_back( + ControlValue(SPLIT_VOLL_KEY,-3)); + result.controlValues().push_back( + ControlValue(SPLIT_PANR_KEY,0)); + result.controlValues().push_back( + ControlValue(SPLIT_VOLR_KEY,-3)); + + return result; +} + + + +PedalBoard PedalBoard::MakeDefault() +{ + // copy insanity. but it happens so rarely. + PedalBoard result; + + auto split = result.MakeSplit(); + split.topChain().push_back(result.MakeEmptyItem()); + split.bottomChain().push_back(result.MakeEmptyItem()); + + + result.items().push_back(result.MakeEmptyItem()); + result.items().push_back(result.MakeEmptyItem()); + result.items().push_back(result.MakeEmptyItem()); + + result.items().push_back(split); + + result.items().push_back(result.MakeEmptyItem()); + result.items().push_back(result.MakeEmptyItem()); + result.items().push_back(result.MakeEmptyItem()); + result.name("Default Preset"); + + return result; +} + + + + + + + + + +JSON_MAP_BEGIN(ControlValue) + JSON_MAP_REFERENCE(ControlValue,key) + JSON_MAP_REFERENCE(ControlValue,value) +JSON_MAP_END() + + +bool IsPedalBoardSplitItem(const PedalBoardItem*self, const std::vector&value) +{ + return self->uri() == SPLIT_PEDALBOARD_ITEM_URI; +} + +JSON_MAP_BEGIN(PedalBoardItem) + JSON_MAP_REFERENCE(PedalBoardItem,instanceId) + JSON_MAP_REFERENCE(PedalBoardItem,uri) + JSON_MAP_REFERENCE(PedalBoardItem,isEnabled) + JSON_MAP_REFERENCE(PedalBoardItem,controlValues) + JSON_MAP_REFERENCE(PedalBoardItem,pluginName) + JSON_MAP_REFERENCE_CONDITIONAL(PedalBoardItem,topChain,IsPedalBoardSplitItem) + JSON_MAP_REFERENCE_CONDITIONAL(PedalBoardItem,bottomChain,&IsPedalBoardSplitItem) + JSON_MAP_REFERENCE(PedalBoardItem,midiBindings) +JSON_MAP_END() + + +JSON_MAP_BEGIN(PedalBoard) + JSON_MAP_REFERENCE(PedalBoard,name) + JSON_MAP_REFERENCE(PedalBoard,items) + JSON_MAP_REFERENCE(PedalBoard,nextInstanceId) +JSON_MAP_END() + diff --git a/src/PedalBoard.hpp b/src/PedalBoard.hpp new file mode 100644 index 0000000..b0c6e55 --- /dev/null +++ b/src/PedalBoard.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include "json.hpp" +#include "MidiBinding.hpp" + +namespace pipedal { + +#define SPLIT_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Split" +#define EMPTY_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Empty" + +#define SPLIT_SPLITTYPE_KEY "splitType" +#define SPLIT_SELECT_KEY "select" +#define SPLIT_MIX_KEY "mix" +#define SPLIT_PANL_KEY "panL" +#define SPLIT_VOLL_KEY "volL" +#define SPLIT_PANR_KEY "panR" +#define SPLIT_VOLR_KEY "volR" + + +#define GETTER_SETTER_REF(name) \ + const decltype(name##_)& name() const { return name##_;} \ + void name(const decltype(name##_) &value) { name##_ = value; } + +#define GETTER_SETTER_VEC(name) \ + decltype(name##_)& name() { return name##_;} \ + const decltype(name##_)& name() const { return name##_;} + + + +#define GETTER_SETTER(name) \ + decltype(name##_) name() const { return name##_;} \ + void name(decltype(name##_) value) { name##_ = value; } + +class ControlValue { +private: + std::string key_; + float value_; +public: + ControlValue() + { + + } + ControlValue(const char*key, float value) + :key_(key) + , value_(value) + { + + } + GETTER_SETTER_REF(key) + GETTER_SETTER_REF(value) + + DECLARE_JSON_MAP(ControlValue); + + +}; + +class PedalBoardItem: public JsonWritable { + long instanceId_ = 0; + std::string uri_; + std::string pluginName_; + bool isEnabled_ = true; + std::vector controlValues_; + std::vector topChain_; + std::vector bottomChain_; + std::vector midiBindings_; +public: + ControlValue*GetControlValue(const std::string&symbol); + GETTER_SETTER(instanceId) + GETTER_SETTER_REF(uri) + GETTER_SETTER_REF(pluginName) + GETTER_SETTER(isEnabled) + GETTER_SETTER_VEC(controlValues) + GETTER_SETTER_VEC(topChain) + GETTER_SETTER_VEC(bottomChain) + GETTER_SETTER_VEC(midiBindings) + + + bool isSplit() const + { + return uri_ == SPLIT_PEDALBOARD_ITEM_URI; + } + bool isEmpty() const { + return uri_ == EMPTY_PEDALBOARD_ITEM_URI; + } + + virtual void write_members(json_writer&writer) const { + writer.write_member("instanceId",instanceId_); + writer.write_member("uri",uri_); + writer.write_member("pluginName",pluginName_); + writer.write_member("isEnabled",isEnabled_); + writer.write_member("controlValues",controlValues_); + if (isSplit()) + { + writer.write_member("topChain",topChain_); + writer.write_member("bottomChain",bottomChain_); + } + } + + DECLARE_JSON_MAP(PedalBoardItem); +}; + + +class PedalBoard { + std::string name_; + std::vector items_; + long nextInstanceId_ = 0; + long NextInstanceId() { return ++nextInstanceId_; } + +public: + bool SetControlValue(long pedalItemId, const std::string &symbol, float value); + bool SetItemEnabled(long pedalItemId, bool enabled); + + PedalBoardItem*GetItem(long pedalItemId); + const PedalBoardItem*GetItem(long pedalItemId) const; + + bool HasItem(long pedalItemid) const { return GetItem(pedalItemid) != nullptr; } + + GETTER_SETTER_REF(name) + GETTER_SETTER_VEC(items) + + + DECLARE_JSON_MAP(PedalBoard); + + PedalBoardItem MakeEmptyItem(); + PedalBoardItem MakeSplit(); + + + static PedalBoard MakeDefault(); +}; + +#undef GETTER_SETTER_REF +#undef GETTER_SETTER_VEC +#undef GETTER_SETTER + + + +} // namespace pipedal \ No newline at end of file diff --git a/src/PiPedalConfiguration.cpp b/src/PiPedalConfiguration.cpp new file mode 100644 index 0000000..4a411eb --- /dev/null +++ b/src/PiPedalConfiguration.cpp @@ -0,0 +1,20 @@ +#include "pch.h" +#include "PiPedalConfiguration.hpp" +#include "json.hpp" + + +using namespace pipedal; + +JSON_MAP_BEGIN(PiPedalConfiguration) +JSON_MAP_REFERENCE(PiPedalConfiguration, lv2_path) +JSON_MAP_REFERENCE(PiPedalConfiguration, local_storage_path) +JSON_MAP_REFERENCE(PiPedalConfiguration, mlock) +JSON_MAP_REFERENCE(PiPedalConfiguration, reactServerAddresses) +JSON_MAP_REFERENCE(PiPedalConfiguration, socketServerAddress) +JSON_MAP_REFERENCE(PiPedalConfiguration, threads) +JSON_MAP_REFERENCE(PiPedalConfiguration, logLevel) +JSON_MAP_REFERENCE(PiPedalConfiguration, logHttpRequests) +JSON_MAP_REFERENCE(PiPedalConfiguration, maxUploadSize) +JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointGateway) +JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointServerAddress) +JSON_MAP_END() diff --git a/src/PiPedalConfiguration.hpp b/src/PiPedalConfiguration.hpp new file mode 100644 index 0000000..32e9e33 --- /dev/null +++ b/src/PiPedalConfiguration.hpp @@ -0,0 +1,116 @@ +#pragma once +#include "json.hpp" +#include +#include +#include "PiPedalException.hpp" +#include +#include +#include +#include "Lv2Log.hpp" +#include + +namespace pipedal { + + +class PiPedalConfiguration +{ +private: + std::string lv2_path_ = "/usr/lib/lv2:/usr/local/lib/lv2"; + std::filesystem::path docRoot_; + std::string local_storage_path_; + bool mlock_ = true; + std::vector reactServerAddresses_ = {"*:5000"}; + std::string socketServerAddress_ = "0.0.0.0:8080"; + uint32_t threads_ = 5; + bool logHttpRequests_ = false; + int logLevel_ = 0; + uint64_t maxUploadSize_ = 1024*1024; + std::string accessPointGateway_; + std::string accessPointServerAddress_; + +public: + + std::filesystem::path GetConfigFilePath() const { + return docRoot_ / "config.jason"; + } + void Load(std::filesystem::path path) { + std::filesystem::path configPath = path / "config.json"; + if (!std::filesystem::exists(configPath)) + { + throw PiPedalException("File not found."); + } + std::ifstream f(configPath); + if (!f.is_open()) + { + std::stringstream s; + s << "Unable to open " << configPath; + throw PiPedalStateException(s.str()); + } + json_reader reader(f); + reader.read(this); + docRoot_ = path; + + } + const std::filesystem::path &GetDocRoot() const { return docRoot_; } + const std::string &GetLv2Path() const { return lv2_path_; } + const std::string &GetLocalStoragePath() const { return local_storage_path_; } + const std::vector &GetReactServerAddresses() const { return reactServerAddresses_;} + bool GetMLock() const { return mlock_; } + uint64_t GetMaxUploadSize() const { return maxUploadSize_; } + + LogLevel GetLogLevel() const { return (LogLevel)this->logLevel_; } + + bool LogHttpRequests() const { return this->logHttpRequests_; } + + void SetSocketServerEndpoint(const std::string &endpoint) + { + this->socketServerAddress_ = endpoint; + } + + bool GetAccessPointGateway(boost::asio::ip::network_v4 *pGatewayNetwork) const { + if (this->accessPointGateway_.length() == 0) return false; + *pGatewayNetwork = boost::asio::ip::make_network_v4(this->accessPointGateway_.c_str()); + return true; + } + std::string GetAccessPointServerAddress() const { return this->accessPointServerAddress_; } + std::string GetSocketServerAddress() const { + size_t pos = this->socketServerAddress_.find_last_of(':'); + if (pos == std::string::npos) + { + return socketServerAddress_; + } + return socketServerAddress_.substr(0,pos); + } + uint16_t GetSocketServerPort() const { + try { + size_t pos = this->socketServerAddress_.find_last_of(':'); + if (pos == std::string::npos) + { + throw std::exception(); + } + std::string strPort = socketServerAddress_.substr(pos+1); + unsigned long port = std::stoul(strPort); + if (port == 0) + { + throw std::exception(); + } + if (port > std::numeric_limits::max()) + { + throw std::exception(); + } + return (uint16_t) port; + } catch (const std::exception &) + { + std::stringstream s; + s << "Invalid port number in '" << this->socketServerAddress_ << "'."; + throw PiPedalArgumentException(s.str()); + } + + } + uint32_t GetThreads() const { return threads_; } + + DECLARE_JSON_MAP(PiPedalConfiguration); +}; + + +}; \ No newline at end of file diff --git a/src/PiPedalException.hpp b/src/PiPedalException.hpp new file mode 100644 index 0000000..c8a945a --- /dev/null +++ b/src/PiPedalException.hpp @@ -0,0 +1,51 @@ +#pragma once +#include + +namespace pipedal +{ + + class PiPedalException : public std::exception + { + std::string what_; + + public: + PiPedalException(const std::string &what) + : std::exception(), what_(what) + { + } + virtual ~PiPedalException() { + + } + virtual const char *what() const noexcept { return what_.c_str(); } + }; + + class PiPedalArgumentException : public PiPedalException + { + public: + PiPedalArgumentException() + : PiPedalException("Invalid argument") + { + } + PiPedalArgumentException(std::string &&what) + : PiPedalException(std::forward(what)) + { + } + }; + class PiPedalStateException : public PiPedalException + { + public: + PiPedalStateException(std::string &&what) + : PiPedalException(std::forward(what)) + { + } + }; + class PiPedalLogicException : public PiPedalException + { + public: + PiPedalLogicException(const char *what) + : PiPedalException(what) + { + } + }; + +} // namespace \ No newline at end of file diff --git a/src/PiPedalMath.hpp b/src/PiPedalMath.hpp new file mode 100644 index 0000000..3102509 --- /dev/null +++ b/src/PiPedalMath.hpp @@ -0,0 +1,18 @@ +#pragma once +#include + +namespace pipedal { + + const double DB0=-96; + + inline float db2a(float db) + { + return std::pow(10,db/20); + } + inline float a2db(float amplitude) + { + if (amplitude == 0) return DB0; + return 20*std::log10(std::abs(amplitude)); + } + +} // namespace \ No newline at end of file diff --git a/src/PiPedalModel.cpp b/src/PiPedalModel.cpp new file mode 100644 index 0000000..f128da9 --- /dev/null +++ b/src/PiPedalModel.cpp @@ -0,0 +1,986 @@ +#include "pch.h" + +#include "PiPedalModel.hpp" +#include "JackHost.hpp" +#include "Lv2Log.hpp" +#include +#include "PiPedalConfiguration.hpp" +#include "ShutdownClient.hpp" +#include "SplitEffect.hpp" + +#ifndef NO_MLOCK +#include +#endif /* NO_MLOCK */ + +using namespace pipedal; + +template +T &constMutex(const T &mutex) +{ + return const_cast(mutex); +} + +std::string AtomToJson(int length, uint8_t *pData) +{ + return ""; +} + +PiPedalModel::PiPedalModel() +{ + this->pedalBoard = PedalBoard::MakeDefault(); +} + +void PiPedalModel::Close() +{ + std::lock_guard lock(this->mutex); + + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->Close(); + } + delete[] t; + + if (jackHost) + { + jackHost->Close(); + } +} + +PiPedalModel::~PiPedalModel() +{ + if (jackHost) + { + jackHost->Close(); + } +} + +#include + +void PiPedalModel::Load(const PiPedalConfiguration &configuration) +{ + + this->jackServerSettings.ReadJackConfiguration(); + + storage.SetDataRoot(configuration.GetLocalStoragePath().c_str()); + storage.Initialize(); + + // Not all Lv2 directories have the lv2 base declarations. Load a full set of plugin classes generated on a default /usr/local/lib/lv2 directory. + std::filesystem::path pluginClassesPath = configuration.GetDocRoot() / "plugin_classes.json"; + try + { + if (!std::filesystem::exists(pluginClassesPath)) + throw PiPedalException("File not found."); + lv2Host.LoadPluginClassesFromJson(pluginClassesPath); + } + catch (const std::exception &e) + { + std::stringstream s; + s << "Unable to load " << pluginClassesPath << ". " << e.what(); + throw PiPedalException(s.str().c_str()); + } + lv2Host.Load(configuration.GetLv2Path().c_str()); + + this->pedalBoard = storage.GetCurrentPreset(); + updateDefaults(&this->pedalBoard); + + std::unique_ptr p{JackHost::CreateInstance(lv2Host.asIHost())}; + this->jackHost = std::move(p); + + this->jackHost->SetNotificationCallbacks(this); + + + if (configuration.GetMLock()) + { +#ifndef NO_MLOCK + int result = mlockall(MCL_CURRENT | MCL_FUTURE); + if (result) + { + throw PiPedalStateException("mlockall failed. You can disable the call to mlockall in 'config.json'."); + } + +#endif + } + + this->jackConfiguration = jackHost->GetServerConfiguration(); + if (this->jackConfiguration.isValid()) + { + JackChannelSelection selection = storage.GetJackChannelSelection(jackConfiguration); + selection = selection.RemoveInvalidChannels(jackConfiguration); + + this->lv2Host.OnConfigurationChanged(jackConfiguration, selection); + try + { + jackHost->Open(selection); + + std::shared_ptr lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)}; + this->lv2PedalBoard = lv2PedalBoard; + jackHost->SetPedalBoard(lv2PedalBoard); + } + catch (PiPedalException &e) + { + Lv2Log::error("Failed to load initial plugin. (%s)", e.what()); + + } + } + +} + +IPiPedalModelSubscriber *PiPedalModel::GetNotificationSubscriber(int64_t clientId) +{ + for (size_t i = 0; i < subscribers.size(); ++i) + { + if (subscribers[i]->GetClientId() == clientId) + { + return subscribers[i]; + } + } + return nullptr; +} + +void PiPedalModel::AddNotificationSubscription(IPiPedalModelSubscriber *pSubscriber) +{ + std::lock_guard lock(this->mutex); + this->subscribers.push_back(pSubscriber); +} +void PiPedalModel::RemoveNotificationSubsription(IPiPedalModelSubscriber *pSubscriber) +{ + { + std::lock_guard lock(this->mutex); + + for (auto it = this->subscribers.begin(); it != this->subscribers.end(); ++it) + { + if ((*it) == pSubscriber) + { + this->subscribers.erase(it); + break; + } + } + int64_t clientId = pSubscriber->GetClientId(); + + this->deleteMidiListeners(clientId); + + for (int i = 0; i < this->outstandingParameterRequests.size(); ++i) + { + if (outstandingParameterRequests[i]->clientId == clientId) + { + outstandingParameterRequests.erase(outstandingParameterRequests.begin() + i); + --i; + } + } + } +} + +void PiPedalModel::previewControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value) +{ + + jackHost->SetControlValue(pedalItemId, symbol, value); +} + +void PiPedalModel::setControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value) +{ + { + std::lock_guard guard(mutex); + previewControl(clientId, pedalItemId, symbol, value); + this->pedalBoard.SetControlValue(pedalItemId, symbol, value); + { + + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnControlChanged(clientId, pedalItemId, symbol, value); + } + delete[] t; + + this->setPresetChanged(clientId, true); + } + } +} + +void PiPedalModel::fireJackConfigurationChanged(const JackConfiguration &jackConfiguration) +{ + // noify subscribers. + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnJackConfigurationChanged(jackConfiguration); + } + delete[] t; +} + +void PiPedalModel::fireBanksChanged(int64_t clientId) +{ + // noify subscribers. + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnBankIndexChanged(this->storage.GetBanks()); + } + delete[] t; +} + +void PiPedalModel::firePedalBoardChanged(int64_t clientId) +{ + // noify subscribers. + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnPedalBoardChanged(clientId, this->pedalBoard); + } + delete[] t; + + // notify the audio thread. + if (jackHost->IsOpen()) + { + std::shared_ptr lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)}; + this->lv2PedalBoard = lv2PedalBoard; + jackHost->SetPedalBoard(lv2PedalBoard); + updateRealtimeVuSubscriptions(); + updateRealtimeMonitorPortSubscriptions(); + } +} +void PiPedalModel::setPedalBoard(int64_t clientId, PedalBoard &pedalBoard) +{ + { + std::lock_guard guard(this->mutex); + this->pedalBoard = pedalBoard; + updateDefaults(&this->pedalBoard); + + this->firePedalBoardChanged(clientId); + this->setPresetChanged(clientId, true); + } +} + + +void PiPedalModel::setPedalBoardItemEnable(int64_t clientId, int64_t pedalItemId, bool enabled) +{ + std::lock_guard(this->mutex); + { + this->pedalBoard.SetItemEnabled(pedalItemId, enabled); + + // Notify clients. + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnItemEnabledChanged(clientId, pedalItemId, enabled); + } + delete[] t; + this->setPresetChanged(clientId, true); + + // Notify audo thread. + this->jackHost->SetBypass(pedalItemId, enabled); + } +} + +void PiPedalModel::getPresets(PresetIndex *pResult) +{ + std::lock_guard guard(mutex); + + this->storage.GetPresetIndex(pResult); + pResult->presetChanged(this->hasPresetChanged); +} + +PedalBoard PiPedalModel::getPreset(int64_t instanceId) +{ + std::lock_guard guard(mutex); + return this->storage.GetPreset(instanceId); +} + + +void PiPedalModel::setPresetChanged(int64_t clientId, bool value) +{ + if (value != this->hasPresetChanged) + { + hasPresetChanged = value; + firePresetsChanged(clientId); + } +} + +void PiPedalModel::firePresetsChanged(int64_t clientId) +{ + std::lock_guard(this->mutex); + { + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + + PresetIndex presets; + getPresets(&presets); + + for (size_t i = 0; i < n; ++i) + { + t[i]->OnPresetsChanged(clientId, presets); + } + delete[] t; + } +} + +void PiPedalModel::saveCurrentPreset(int64_t clientId) +{ + std::lock_guard(this->mutex); + + storage.saveCurrentPreset(this->pedalBoard); + this->setPresetChanged(clientId, false); +} + +int64_t PiPedalModel::saveCurrentPresetAs(int64_t clientId, const std::string &name, int64_t saveAfterInstanceId) +{ + std::lock_guard(this->mutex); + + int64_t result = storage.saveCurrentPresetAs(this->pedalBoard, name, saveAfterInstanceId); + this->hasPresetChanged = false; + firePresetsChanged(clientId); + return result; +} + +int64_t PiPedalModel::uploadPreset(const BankFile&bankFile,int64_t uploadAfter) +{ + std::lock_guard(this->mutex); + + int64_t newPreset = this->storage.UploadPreset(bankFile,uploadAfter); + firePresetsChanged(-1); + return newPreset; + +} + +void PiPedalModel::loadPreset(int64_t clientId, int64_t instanceId) +{ + std::lock_guard(this->mutex); + + if (storage.LoadPreset(instanceId)) + { + this->pedalBoard = storage.GetCurrentPreset(); + updateDefaults(&this->pedalBoard); + + this->hasPresetChanged = false; // no fire. + this->firePedalBoardChanged(clientId); + this->firePresetsChanged(clientId); // fire now. + } +} + +int64_t PiPedalModel::copyPreset(int64_t clientId, int64_t from, int64_t to) +{ + std::lock_guard(this->mutex); + + int64_t result = storage.CopyPreset(from, to); + if (result != -1) + { + this->firePresetsChanged(clientId); // fire now. + } + else + { + throw PiPedalStateException("Copy failed."); + } + return result; +} +bool PiPedalModel::updatePresets(int64_t clientId, const PresetIndex &presets) +{ + std::lock_guard(this->mutex); + storage.SetPresetIndex(presets); + firePresetsChanged(clientId); + return true; +} + +void PiPedalModel::moveBank(int64_t clientId, int from, int to) +{ + std::lock_guard(this->mutex); + storage.MoveBank(from, to); + fireBanksChanged(clientId); +} +int64_t PiPedalModel::deleteBank(int64_t clientId, int64_t instanceId) +{ + std::lock_guard(this->mutex); + int64_t selectedBank = this->storage.GetBanks().selectedBank(); + int64_t newSelection = storage.DeleteBank(instanceId); + + int64_t newSelectedBank = this->storage.GetBanks().selectedBank(); + + this->fireBanksChanged(clientId); // fire now. + + if (newSelectedBank != selectedBank) + { + this->openBank(clientId, newSelectedBank); + } + return newSelection; +} + +int64_t PiPedalModel::deletePreset(int64_t clientId, int64_t instanceId) +{ + std::lock_guard(this->mutex); + + int64_t newSelection = storage.DeletePreset(instanceId); + this->firePresetsChanged(clientId); // fire now. + return newSelection; +} +bool PiPedalModel::renamePreset(int64_t clientId, int64_t instanceId, const std::string &name) +{ + std::lock_guard guard(mutex); + if (storage.RenamePreset(instanceId, name)) + { + this->firePresetsChanged(clientId); + return true; + } + else + { + throw PiPedalStateException("Rename failed."); + } +} + +JackConfiguration PiPedalModel::getJackConfiguration() +{ + std::lock_guard lock(this->mutex); // copy atomically. + return this->jackConfiguration; +} + +void PiPedalModel::setJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection) +{ + std::lock_guard lock(this->mutex); // copy atomically. + this->storage.SetJackChannelSelection(channelSelection); + this->fireChannelSelectionChanged(clientId); + + this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection); + if (this->jackHost->IsOpen()) + { + // do a complete reload. + + this->jackHost->Close(); + this->jackHost->SetPedalBoard(nullptr); + this->jackHost->Open(channelSelection); + std::shared_ptr lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)}; + this->lv2PedalBoard = lv2PedalBoard; + jackHost->SetPedalBoard(lv2PedalBoard); + this->updateRealtimeVuSubscriptions(); + } +} + +void PiPedalModel::fireChannelSelectionChanged(int64_t clientId) +{ + std::lock_guard(this->mutex); + { + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + + JackChannelSelection channelSelection = storage.GetJackChannelSelection(this->jackConfiguration); + + for (size_t i = 0; i < n; ++i) + { + t[i]->OnChannelSelectionChanged(clientId, channelSelection); + } + delete[] t; + } +} + +JackChannelSelection PiPedalModel::getJackChannelSelection() +{ + std::lock_guard guard(mutex); + JackChannelSelection t = this->storage.GetJackChannelSelection(this->jackConfiguration); + if (this->jackConfiguration.isValid()) + { + t = t.RemoveInvalidChannels(this->jackConfiguration); + } + return t; +} + +int64_t PiPedalModel::addVuSubscription(int64_t instanceId) +{ + std::lock_guard guard(mutex); + int64_t subscriptionId = ++nextSubscriptionId; + activeVuSubscriptions.push_back(VuSubscription{subscriptionId, instanceId}); + + updateRealtimeVuSubscriptions(); + + return subscriptionId; +} +void PiPedalModel::removeVuSubscription(int64_t subscriptionHandle) +{ + std::lock_guard guard(mutex); + for (auto i = activeVuSubscriptions.begin(); i != activeVuSubscriptions.end(); ++i) + { + if ((*i).subscriptionHandle == subscriptionHandle) + { + activeVuSubscriptions.erase(i); + break; + } + } + updateRealtimeVuSubscriptions(); +} + +void PiPedalModel::OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, float value) +{ + std::lock_guard guard(mutex); + PedalBoardItem *item = this->pedalBoard.GetItem(instanceId); + if (item) + { + const Lv2PluginInfo *pPluginInfo; + if (item->uri() == SPLIT_PEDALBOARD_ITEM_URI) + { + pPluginInfo = GetSplitterPluginInfo(); + } + else + { + auto pluginInfo = lv2Host.GetPluginInfo(item->uri()); + pPluginInfo = pluginInfo.get(); + } + if (pPluginInfo) + { + if (portIndex == -1) + { + // bypass! + this->pedalBoard.SetItemEnabled(instanceId, value != 0); + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnItemEnabledChanged(-1, instanceId, value != 0); + } + delete[] t; + + this->setPresetChanged(-1, true); + return; + } + else + { + for (int i = 0; i < pPluginInfo->ports().size(); ++i) + { + auto &port = pPluginInfo->ports()[i]; + if (port->index() == portIndex) + { + std::string symbol = port->symbol(); + + this->pedalBoard.SetControlValue(instanceId, symbol, value); + { + + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnMidiValueChanged(instanceId, symbol, value); + } + delete[] t; + + this->setPresetChanged(-1, true); + return; + } + } + } + } + } + } +} +void PiPedalModel::OnNotifyVusSubscription(const std::vector &updates) +{ + std::lock_guard guard(mutex); + for (size_t i = 0; i < updates.size(); ++i) + { + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnVuMeterUpdate(updates); + } + delete[] t; + } +} + +void PiPedalModel::updateRealtimeVuSubscriptions() +{ + std::set addedInstances; + + for (int i = 0; i < activeVuSubscriptions.size(); ++i) + { + auto instanceId = activeVuSubscriptions[i].instanceid; + if (pedalBoard.HasItem(instanceId)) + { + addedInstances.insert(activeVuSubscriptions[i].instanceid); + } + } + std::vector instanceids(addedInstances.begin(), addedInstances.end()); + jackHost->SetVuSubscriptions(instanceids); +} + +void PiPedalModel::updateRealtimeMonitorPortSubscriptions() +{ + jackHost->SetMonitorPortSubscriptions(this->activeMonitorPortSubscriptions); +} + +int64_t PiPedalModel::monitorPort(int64_t instanceId, const std::string &key, float updateInterval, PortMonitorCallback onUpdate) +{ + std::lock_guard guard(mutex); + int64_t subscriptionId = ++nextSubscriptionId; + activeMonitorPortSubscriptions.push_back( + MonitorPortSubscription{subscriptionId, instanceId, key, updateInterval, onUpdate}); + + updateRealtimeMonitorPortSubscriptions(); + + return subscriptionId; +} +void PiPedalModel::unmonitorPort(int64_t subscriptionHandle) +{ + std::lock_guard guard(mutex); + + for (auto i = activeMonitorPortSubscriptions.begin(); i != activeMonitorPortSubscriptions.end(); ++i) + { + if ((*i).subscriptionHandle == subscriptionHandle) + { + activeMonitorPortSubscriptions.erase(i); + updateRealtimeMonitorPortSubscriptions(); + break; + } + } +} +void PiPedalModel::OnNotifyMonitorPort(const MonitorPortUpdate &update) +{ + std::lock_guard guard(mutex); + + for (auto i = activeMonitorPortSubscriptions.begin(); i != activeMonitorPortSubscriptions.end(); ++i) + { + if ((*i).subscriptionHandle == update.subscriptionHandle) + { + + // make the call ONLY if the subscription handle is still valid. + (*update.callbackPtr)(update.subscriptionHandle, update.value); + break; + } + } +} + +void PiPedalModel::getLv2Parameter( + int64_t clientId, + int64_t instanceId, + const std::string uri, + std::function onSuccess, + std::function onError) +{ + std::function onRequestComplete{ + [this](RealtimeParameterRequest *pParameter) + { + { + std::lock_guard guard(this->mutex); + bool cancelled = true; + for (auto i = this->outstandingParameterRequests.begin(); + i != this->outstandingParameterRequests.end(); ++i) + { + if ((*i) == pParameter) + { + cancelled = false; + this->outstandingParameterRequests.erase(i); + break; + } + } + if (!cancelled) + { + if (pParameter->errorMessage != nullptr) + { + pParameter->onError(pParameter->errorMessage); + } + else if (pParameter->responseLength == 0) + { + pParameter->onError("No response."); + } + else + { + pParameter->onSuccess(pParameter->jsonResponse); + } + } + delete pParameter; + } + }}; + + LV2_URID urid = this->lv2Host.GetLv2Urid(uri.c_str()); + RealtimeParameterRequest *request = new RealtimeParameterRequest( + onRequestComplete, + clientId, instanceId, urid, onSuccess, onError); + + std::lock_guard guard(constMutex(mutex)); + outstandingParameterRequests.push_back(request); + this->jackHost->getRealtimeParameter(request); +} + +BankIndex PiPedalModel::getBankIndex() const +{ + std::lock_guard guard(constMutex(mutex)); + return storage.GetBanks(); +} + +void PiPedalModel::renameBank(int64_t clientId, int64_t bankId, const std::string &newName) +{ + std::lock_guard guard(mutex); + storage.RenameBank(bankId, newName); + fireBanksChanged(clientId); +} + +int64_t PiPedalModel::saveBankAs(int64_t clientId, int64_t bankId, const std::string &newName) +{ + std::lock_guard guard(mutex); + int64_t newId = storage.SaveBankAs(bankId, newName); + fireBanksChanged(clientId); + return newId; +} + +void PiPedalModel::openBank(int64_t clientId, int64_t bankId) +{ + std::lock_guard guard(mutex); + + storage.LoadBank(bankId); + fireBanksChanged(clientId); + + firePresetsChanged(clientId); + + this->pedalBoard = storage.GetCurrentPreset(); + updateDefaults(&this->pedalBoard); + this->hasPresetChanged = false; + this->firePedalBoardChanged(clientId); +} + +JackServerSettings PiPedalModel::GetJackServerSettings() +{ + std::lock_guard guard(mutex); + return this->jackServerSettings; +} + +void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSettings) +{ + std::lock_guard guard(mutex); + + this->jackServerSettings = jackServerSettings; + + if (!ShutdownClient::CanUseShutdownClient()) + { + throw PiPedalException("Can't change server settings when running interactively."); + } + + // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnJackServerSettingsChanged(jackServerSettings); + } + delete[] t; + + if (ShutdownClient::CanUseShutdownClient()) + { + this->jackConfiguration.SetIsRestarting(true); + fireJackConfigurationChanged(this->jackConfiguration); + this->jackHost->UpdateServerConfiguration(jackServerSettings, + [this](bool success, const std::string &errorMessage) + { + std::lock_guard guard(mutex); + if (!success) + { + std::stringstream s; + s << "UpdateServerconfiguration failed: " << errorMessage; + Lv2Log::error(s.str().c_str()); + } + // Update jack server status. + this->jackConfiguration.SetIsRestarting(false); + fireJackConfigurationChanged(this->jackConfiguration); + + // restart the pedalboard on a new instance. + std::shared_ptr lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)}; + this->lv2PedalBoard = lv2PedalBoard; + + jackHost->SetPedalBoard(lv2PedalBoard); + updateRealtimeVuSubscriptions(); + updateRealtimeMonitorPortSubscriptions(); + }); + } +} + +void PiPedalModel::updateDefaults(PedalBoardItem *pedalBoardItem) +{ + std::shared_ptr t = lv2Host.GetPluginInfo(pedalBoardItem->uri()); + const Lv2PluginInfo *pPlugin = t.get(); + if (pPlugin == nullptr) + { + if (pedalBoardItem->uri() == SPLIT_PEDALBOARD_ITEM_URI) + { + pPlugin = GetSplitterPluginInfo(); + } + } + if (pPlugin != nullptr) + { + for (size_t i = 0; i < pPlugin->ports().size(); ++i) + { + auto port = pPlugin->ports()[i]; + if (port->is_control_port() && port->is_input()) + { + ControlValue *pValue = pedalBoardItem->GetControlValue(port->symbol()); + if (pValue == nullptr) + { + // Missing? Set it to default value. + pedalBoardItem->controlValues().push_back( + pipedal::ControlValue(port->symbol().c_str(), port->default_value())); + } + } + } + } + for (size_t i = 0; i < pedalBoardItem->topChain().size(); ++i) + { + updateDefaults(&(pedalBoardItem->topChain()[i])); + } + for (size_t i = 0; i < pedalBoardItem->bottomChain().size(); ++i) + { + updateDefaults(&(pedalBoardItem->bottomChain()[i])); + } +} +void PiPedalModel::updateDefaults(PedalBoard *pedalBoard) +{ + for (size_t i = 0; i < pedalBoard->items().size(); ++i) + { + updateDefaults(&(pedalBoard->items()[i])); + } +} + +std::vector PiPedalModel::GetPluginPresets(std::string pluginUri) +{ + std::lock_guard guard(mutex); + + return lv2Host.GetPluginPresets(pluginUri); +} + +void PiPedalModel::LoadPluginPreset(int64_t instanceId, const std::string &presetUri) +{ + std::lock_guard guard(mutex); + + PedalBoardItem *pedalBoardItem = this->pedalBoard.GetItem(instanceId); + if (pedalBoardItem != nullptr) + { + std::vector controlValues = lv2Host.LoadPluginPreset(pedalBoardItem, presetUri); + jackHost->SetPluginPreset(instanceId, controlValues); + + for (size_t i = 0; i < controlValues.size(); ++i) + { + const ControlValue &value = controlValues[i]; + this->pedalBoard.SetControlValue(instanceId, value.key(), value.value()); + } + + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + for (size_t i = 0; i < n; ++i) + { + t[i]->OnLoadPluginPreset(instanceId, controlValues); + } + delete[] t; + } +} + +void PiPedalModel::deleteMidiListeners(int64_t clientId) +{ + std::lock_guard guard(mutex); + for (size_t i = 0; i < midiEventListeners.size(); ++i) + { + if (midiEventListeners[i].clientId == clientId) + { + midiEventListeners.erase(midiEventListeners.begin() + i); + --i; + } + } + jackHost->SetListenForMidiEvent(midiEventListeners.size() != 0); +} + +void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl) +{ + std::lock_guard guard(mutex); + + for (int i = 0; i < midiEventListeners.size(); ++i) + { + auto &listener = midiEventListeners[i]; + if ((!isNote) || (!listener.listenForControlsOnly)) + { + auto subscriber = this->GetNotificationSubscriber(listener.clientId); + if (subscriber) + { + subscriber->OnNotifyMidiListener(listener.clientHandle, isNote, noteOrControl); + } + midiEventListeners.erase(midiEventListeners.begin() + i); + --i; + } + } + jackHost->SetListenForMidiEvent(midiEventListeners.size() != 0); +} + +void PiPedalModel::listenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly) +{ + std::lock_guard guard(mutex); + MidiListener listener{clientId, clientHandle, listenForControlsOnly}; + midiEventListeners.push_back(listener); + jackHost->SetListenForMidiEvent(true); +} +void PiPedalModel::cancelListenForMidiEvent(int64_t clientId, int64_t clientHandled) +{ + std::lock_guard guard(mutex); + for (size_t i = 0; i < midiEventListeners.size(); ++i) + { + midiEventListeners.erase(midiEventListeners.begin() + i); + } + if (midiEventListeners.size() == 0) + { + jackHost->SetListenForMidiEvent(false); + } +} + diff --git a/src/PiPedalModel.hpp b/src/PiPedalModel.hpp new file mode 100644 index 0000000..6df567f --- /dev/null +++ b/src/PiPedalModel.hpp @@ -0,0 +1,179 @@ +#pragma once +#include +#include "Lv2Host.hpp" +#include "PedalBoard.hpp" +#include "Storage.hpp" +#include "Banks.hpp" +#include "JackConfiguration.hpp" +#include "JackHost.hpp" +#include "VuUpdate.hpp" +#include +#include +#include "Banks.hpp" +#include "PiPedalConfiguration.hpp" +#include "JackServerSettings.hpp" + + +namespace pipedal { + + + + +class IPiPedalModelSubscriber { +public: + virtual int64_t GetClientId() = 0; + virtual void OnItemEnabledChanged(int64_t clientId, int64_t pedalItemId, bool enabled) = 0; + virtual void OnControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value) = 0; + virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard) = 0; + virtual void OnPresetsChanged(int64_t clientId, const PresetIndex&presets) = 0; + virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection&channelSelection) = 0; + virtual void OnVuMeterUpdate(const std::vector& updates) = 0; + virtual void OnBankIndexChanged(const BankIndex& bankIndex) = 0; + virtual void OnJackServerSettingsChanged(const JackServerSettings& jackServerSettings) = 0; + virtual void OnJackConfigurationChanged(const JackConfiguration& jackServerConfiguration) = 0; + virtual void OnLoadPluginPreset(int64_t instanceId,const std::vector&controlValues) = 0; + virtual void OnMidiValueChanged(int64_t instanceId, const std::string&symbol, float value) = 0; + virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0; + virtual void Close() = 0; +}; + +class PiPedalModel: private IJackHostCallbacks { +private: + + class MidiListener { + public: + int64_t clientId; + int64_t clientHandle; + bool listenForControlsOnly; + }; + void deleteMidiListeners(int64_t clientId); + + std::vector midiEventListeners; + + JackServerSettings jackServerSettings; + Lv2Host lv2Host; + std::recursive_mutex mutex; + PedalBoard pedalBoard; + Storage storage; + bool hasPresetChanged = false; + + std::unique_ptr jackHost; + JackConfiguration jackConfiguration; + std::shared_ptr lv2PedalBoard; + + + std::vector subscribers; + void setPresetChanged(int64_t clientId,bool value); + void firePresetsChanged(int64_t clientId); + void firePedalBoardChanged(int64_t clientId); + void fireChannelSelectionChanged(int64_t clientId); + void fireBanksChanged(int64_t clientId); + void fireJackConfigurationChanged(const JackConfiguration&jackConfiguration); + + void updateDefaults(PedalBoardItem*pedalBoardItem); + void updateDefaults(PedalBoard*pedalBoard); + + + class VuSubscription { + public: + int64_t subscriptionHandle; + int64_t instanceid; + }; + int64_t nextSubscriptionId = 1; + std::vector activeVuSubscriptions; + + std::vector activeMonitorPortSubscriptions; + + void updateRealtimeVuSubscriptions(); + void updateRealtimeMonitorPortSubscriptions(); + void OnVuUpdate(const std::vector& updates); + + std::vector outstandingParameterRequests; + + IPiPedalModelSubscriber*GetNotificationSubscriber(int64_t clientId); + +private: // IJackHostCallbacks + virtual void OnNotifyVusSubscription(const std::vector & updates); + virtual void OnNotifyMonitorPort(const MonitorPortUpdate &update); + virtual void OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, float value); + virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl); + + +public: + PiPedalModel(); + virtual ~PiPedalModel(); + + void Close(); + void Load(const PiPedalConfiguration&configuration); + + const Lv2Host& getPlugins() const { return lv2Host; } + PedalBoard getCurrentPedalBoardCopy() { + std::lock_guard guard(mutex); + return pedalBoard; + } + std::vector GetPluginPresets(std::string pluginUri); + void LoadPluginPreset(int64_t instanceId,const std::string &presetUri); + + void AddNotificationSubscription(IPiPedalModelSubscriber* pSubscriber); + void RemoveNotificationSubsription(IPiPedalModelSubscriber* pSubscriber); + + void setPedalBoardItemEnable(int64_t clientId, int64_t instanceId, bool enabled); + void setControl(int64_t clientId,int64_t pedalItemId, const std::string&symbol,float value); + void previewControl(int64_t clientId,int64_t pedalItemId, const std::string&symbol,float value); + void setPedalBoard(int64_t clientId,PedalBoard &pedalBoard); + + void getPresets(PresetIndex*pResult); + PedalBoard getPreset(int64_t instanceId); + int64_t uploadPreset(const BankFile&bankFile, int64_t uploadAfter = -1); + void saveCurrentPreset(int64_t clientId); + int64_t saveCurrentPresetAs(int64_t clientId, const std::string& name,int64_t saveAfterInstanceId = -1); + + void loadPreset(int64_t clientId, int64_t instanceId); + bool updatePresets(int64_t clientId,const PresetIndex&presets); + int64_t deletePreset(int64_t clientId,int64_t instanceId); + bool renamePreset(int64_t clientId,int64_t instanceId,const std::string&name); + int64_t copyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex); + + void moveBank(int64_t clientId,int from, int to); + int64_t deleteBank(int64_t clientId, int64_t instanceId); + + + int64_t duplicatePreset(int64_t clientId, int64_t instanceId) { return copyPreset(clientId,instanceId,-1); } + + JackConfiguration getJackConfiguration(); + + void setJackChannelSelection(int64_t clientId,const JackChannelSelection &channelSelection); + JackChannelSelection getJackChannelSelection(); + + + int64_t addVuSubscription(int64_t instanceId); + void removeVuSubscription(int64_t subscriptionHandle); + + + int64_t monitorPort(int64_t instanceId,const std::string &key,float updateInterval, PortMonitorCallback onUpdate); + void unmonitorPort(int64_t subscriptionHandle); + + void getLv2Parameter( + int64_t clientId, + int64_t instanceId, + const std::string uri, + std::function onSuccess, + std::function onError + ); + + BankIndex getBankIndex() const; + void renameBank(int64_t clientId,int64_t bankId, const std::string& newName); + int64_t saveBankAs(int64_t clientId,int64_t bankId, const std::string& newName); + void openBank(int64_t clientId,int64_t bankId); + + JackHostStatus getJackStatus() { + return this->jackHost->getJackStatus(); + } + JackServerSettings GetJackServerSettings(); + void SetJackServerSettings(const JackServerSettings& jackServerSettings); + + void listenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly); + void cancelListenForMidiEvent(int64_t clientId, int64_t clientHandled); + +}; +} // namespace pipedal. \ No newline at end of file diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp new file mode 100644 index 0000000..d200c75 --- /dev/null +++ b/src/PiPedalSocket.cpp @@ -0,0 +1,1275 @@ +#include "pch.h" + +#include "PiPedalSocket.hpp" +#include "json.hpp" +#include "viewstream.hpp" +#include "PiPedalVersion.hpp" +#include +#include "Lv2Log.hpp" +#include "JackConfiguration.hpp" +#include +#include + +#include "ShutdownClient.hpp" + +using namespace std; +using namespace pipedal; + + +class NotifyMidiListenerBody { +public: + int64_t clientHandle_; + bool isNote_; + int32_t noteOrControl_; + DECLARE_JSON_MAP(NotifyMidiListenerBody); + +}; +JSON_MAP_BEGIN(NotifyMidiListenerBody) +JSON_MAP_REFERENCE(NotifyMidiListenerBody, clientHandle) +JSON_MAP_REFERENCE(NotifyMidiListenerBody, isNote) +JSON_MAP_REFERENCE(NotifyMidiListenerBody, noteOrControl) +JSON_MAP_END() + +class ListenForMidiEventBody { +public: + bool listenForControlsOnly_; + int64_t handle_; + DECLARE_JSON_MAP(ListenForMidiEventBody); +}; + +JSON_MAP_BEGIN(ListenForMidiEventBody) +JSON_MAP_REFERENCE(ListenForMidiEventBody, listenForControlsOnly) +JSON_MAP_REFERENCE(ListenForMidiEventBody, handle) +JSON_MAP_END() + + +class OnLoadPluginPresetBody { +public: + int64_t instanceId_; + std::vector controlValues_; + DECLARE_JSON_MAP(OnLoadPluginPresetBody); +}; + +JSON_MAP_BEGIN(OnLoadPluginPresetBody) +JSON_MAP_REFERENCE(OnLoadPluginPresetBody, instanceId) +JSON_MAP_REFERENCE(OnLoadPluginPresetBody, controlValues) +JSON_MAP_END() + +class LoadPluginPresetBody { +public: + int64_t instanceId_; + std::string presetName_; + DECLARE_JSON_MAP(LoadPluginPresetBody); +}; + +JSON_MAP_BEGIN(LoadPluginPresetBody) +JSON_MAP_REFERENCE(LoadPluginPresetBody, instanceId) +JSON_MAP_REFERENCE(LoadPluginPresetBody, presetName) +JSON_MAP_END() + +class FromToBody +{ +public: + int64_t from_ = -1; + int64_t to_ = -1; + + DECLARE_JSON_MAP(FromToBody); +}; + +JSON_MAP_BEGIN(FromToBody) +JSON_MAP_REFERENCE(FromToBody, from) +JSON_MAP_REFERENCE(FromToBody, to) +JSON_MAP_END() + +class MonitorResultBody +{ +public: + int64_t subscriptionHandle_ = -1; + float value_; + + DECLARE_JSON_MAP(MonitorResultBody); +}; +JSON_MAP_BEGIN(MonitorResultBody) +JSON_MAP_REFERENCE(MonitorResultBody, subscriptionHandle) +JSON_MAP_REFERENCE(MonitorResultBody, value) +JSON_MAP_END() + + +class GetLv2ParameterBody +{ +public: + int64_t instanceId_; + std::string uri_; + + DECLARE_JSON_MAP(GetLv2ParameterBody); +}; +JSON_MAP_BEGIN(GetLv2ParameterBody) +JSON_MAP_REFERENCE(GetLv2ParameterBody, instanceId) +JSON_MAP_REFERENCE(GetLv2ParameterBody, uri) +JSON_MAP_END() + +class MonitorPortBody +{ +public: + int64_t instanceId_ = -1; + std::string key_; + float_t updateRate_ = 0; + + DECLARE_JSON_MAP(MonitorPortBody); +}; +JSON_MAP_BEGIN(MonitorPortBody) +JSON_MAP_REFERENCE(MonitorPortBody, instanceId) +JSON_MAP_REFERENCE(MonitorPortBody, key) +JSON_MAP_REFERENCE(MonitorPortBody, updateRate) +JSON_MAP_END() + +class SaveCurrentPresetAsBody +{ +public: + int64_t clientId_ = -1; + std::string name_; + int64_t saveAfterInstanceId_ = -1; + + DECLARE_JSON_MAP(SaveCurrentPresetAsBody); +}; +JSON_MAP_BEGIN(SaveCurrentPresetAsBody) +JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, clientId) +JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, name) +JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, saveAfterInstanceId) +JSON_MAP_END() + +class RenameBankBody { +public: + int64_t bankId_; + std::string newName_; + DECLARE_JSON_MAP(RenameBankBody); + +}; +JSON_MAP_BEGIN(RenameBankBody) +JSON_MAP_REFERENCE(RenameBankBody,bankId) +JSON_MAP_REFERENCE(RenameBankBody, newName) +JSON_MAP_END() + +class RenamePresetBody +{ +public: + int64_t clientId_ = -1; + int64_t instanceId_ = -1; + std::string name_; + + DECLARE_JSON_MAP(RenamePresetBody); +}; +JSON_MAP_BEGIN(RenamePresetBody) +JSON_MAP_REFERENCE(RenamePresetBody, clientId) +JSON_MAP_REFERENCE(RenamePresetBody, instanceId) +JSON_MAP_REFERENCE(RenamePresetBody, name) +JSON_MAP_END() + +class CopyPresetBody +{ +public: + int64_t clientId_ = -1; + int64_t fromId_ = -1; + int64_t toId_ = -1; + + DECLARE_JSON_MAP(CopyPresetBody); +}; +JSON_MAP_BEGIN(CopyPresetBody) +JSON_MAP_REFERENCE(CopyPresetBody, clientId) +JSON_MAP_REFERENCE(CopyPresetBody, fromId) +JSON_MAP_REFERENCE(CopyPresetBody, toId) +JSON_MAP_END() + +class PedalBoardItemEnabledBody +{ +public: + int64_t clientId_ = -1; + int64_t instanceId_ = -1; + bool enabled_ = true; + + DECLARE_JSON_MAP(PedalBoardItemEnabledBody); +}; +JSON_MAP_BEGIN(PedalBoardItemEnabledBody) +JSON_MAP_REFERENCE(PedalBoardItemEnabledBody, clientId) +JSON_MAP_REFERENCE(PedalBoardItemEnabledBody, instanceId) +JSON_MAP_REFERENCE(PedalBoardItemEnabledBody, enabled) +JSON_MAP_END() + +class SetCurrentPedalBoardBody +{ +public: + int64_t clientId_ = -1; + PedalBoard pedalBoard_; + + DECLARE_JSON_MAP(SetCurrentPedalBoardBody); +}; + +JSON_MAP_BEGIN(SetCurrentPedalBoardBody) +JSON_MAP_REFERENCE(SetCurrentPedalBoardBody, clientId) +JSON_MAP_REFERENCE(SetCurrentPedalBoardBody, pedalBoard) +JSON_MAP_END() + +class ChannelSelectionChangedBody +{ +public: + int64_t clientId_ = -1; + JackChannelSelection *jackChannelSelection_ = nullptr; + + DECLARE_JSON_MAP(ChannelSelectionChangedBody); +}; +JSON_MAP_BEGIN(ChannelSelectionChangedBody) +JSON_MAP_REFERENCE(ChannelSelectionChangedBody, clientId) +JSON_MAP_REFERENCE(ChannelSelectionChangedBody, jackChannelSelection) +JSON_MAP_END() + +class PresetsChangedBody +{ +public: + int64_t clientId_ = -1; + PresetIndex *presets_ = nullptr; + + DECLARE_JSON_MAP(PresetsChangedBody); +}; +JSON_MAP_BEGIN(PresetsChangedBody) +JSON_MAP_REFERENCE(PresetsChangedBody, clientId) +JSON_MAP_REFERENCE(PresetsChangedBody, presets) +JSON_MAP_END() + +class ControlChangedBody +{ +public: + int64_t clientId_; + int64_t instanceId_; + std::string symbol_; + float value_; + + DECLARE_JSON_MAP(ControlChangedBody); +}; + +JSON_MAP_BEGIN(ControlChangedBody) +JSON_MAP_REFERENCE(ControlChangedBody, clientId) +JSON_MAP_REFERENCE(ControlChangedBody, instanceId) +JSON_MAP_REFERENCE(ControlChangedBody, symbol) +JSON_MAP_REFERENCE(ControlChangedBody, value) +JSON_MAP_END() + + + + +static void requestShutdown(bool restart) +{ + if (ShutdownClient::CanUseShutdownClient()) + { + ShutdownClient::RequestShutdown(restart); + } + else { + // ONLY works when interactively logged in. + std::stringstream s; + s << "/usr/sbin/shutdown "; + if (restart) + { + s << "-r"; + } else + { + s << "-P"; + } + s << " now"; + + if (system(s.str().c_str()) != EXIT_SUCCESS) + { + Lv2Log::error("shutdown failed."); + if (restart) { + throw new PiPedalStateException("Restart request failed."); + } else { + throw new PiPedalStateException("Shutdown request failed."); + } + } + } +} + + +class PiPedalSocketHandler : public SocketHandler, public IPiPedalModelSubscriber +{ +private: + std::recursive_mutex writeMutex; + PiPedalModel &model; + static std::atomic nextClientId; + + uint64_t clientId; + // pedalboard is mutable and not thread-safe. + std::recursive_mutex subscriptionMutex; + struct VuSubscription + { + int64_t subscriptionHandle; + int64_t instanceId; + }; + std::vector activeVuSubscriptions; + + struct PortMonitorSubscription + { + int64_t subscriptionHandle = -1; + int64_t instanceId = -1; + bool waitingForAck = false; + std::string key; + }; + + std::vector activePortMonitors; + +public: + virtual int64_t GetClientId() { return clientId; } + + virtual ~PiPedalSocketHandler() + { + for (int i = 0; i < this->activePortMonitors.size(); ++i) + { + model.unmonitorPort(activePortMonitors[i].subscriptionHandle); + } + for (int i = 0; i < this->activeVuSubscriptions.size(); ++i) + { + model.removeVuSubscription(activeVuSubscriptions[i].subscriptionHandle); + } + + model.RemoveNotificationSubsription(this); + } + + virtual void Close() + { + SocketHandler::Close(); + } + + PiPedalSocketHandler(PiPedalModel &model) + : model(model), clientId(++nextClientId) + { + } + +private: + void JsonReply(int replyTo, const char *message, const char *json) + { + std::stringstream s(ios_base::out); + + json_writer writer(s, true); + + writer.start_array(); + { + writer.start_object(); + { + if (replyTo != -1) + { + writer.write_member("reply", replyTo); + writer.write_raw(","); + } + writer.write_member("message", message); + } + writer.end_object(); + writer.write_raw(","); + writer.write_raw(json); + } + writer.end_array(); + + { + std::lock_guard guard(this->writeMutex); + this->send(s.str()); + } + } + // void JsonSend(const char *message, const char *json) + // { + // JsonReply(-1, message, json); + // } + template + void Reply(int replyTo, const char *message, const T &value) + { + std::stringstream s(ios_base::out); + + json_writer writer(s, true); + writer.start_array(); + { + writer.start_object(); + { + if (replyTo != -1) + { + writer.write_member("reply", replyTo); + writer.write_raw(","); + } + writer.write_member("message", message); + } + writer.end_object(); + writer.write_raw(","); + writer.write(value); + } + writer.end_array(); + { + std::lock_guard guard(this->writeMutex); + this->send(s.str()); + } + } + void Reply(int replyTo, const char *message) + { + if (replyTo == -1) + return; + std::stringstream s(ios_base::out); + + json_writer writer(s, true); + writer.start_array(); + { + writer.start_object(); + { + if (replyTo != -1) + { + writer.write_member("reply", replyTo); + writer.write_raw(","); + } + writer.write_member("message", message); + } + writer.end_object(); + } + writer.end_array(); + + { + std::lock_guard guard(this->writeMutex); + this->send(s.str()); + } + } + +private: + class IRequestReservation + { + int reservationId; + + public: + IRequestReservation(int reservationId) + : reservationId(reservationId) + { + } + int GetReservationid() const { return reservationId; } + virtual ~IRequestReservation() {} + virtual void onResult(json_reader *pReader) = 0; + virtual void onError(const std::exception &e) = 0; + }; + + class RequestReservationBase : public IRequestReservation + { + protected: + virtual void onResult(json_reader &reader) = 0; + }; + template + class RequestReservation : public IRequestReservation + { + public: + using ResponseFn = std::function; + using ErrorFn = std::function; + + private: + ResponseFn responseFn; + bool hasErrorFn; + ErrorFn errorFn; + + virtual void onError(const std::exception &e) + { + if (hasErrorFn) + { + errorFn(e); + } + else + { + throw e; + } + }; + + virtual void onResult(json_reader *pReader) + { + REPLY value; + try + { + if (pReader == nullptr) + { + throw PiPedalException("No value provide for reply."); + } + pReader->read(&value); + responseFn(value); + } + catch (const std::exception &e) + { + onError(e); + } + }; + + public: + RequestReservation(int reservationId, ResponseFn onResponse, ErrorFn errorFn) + : IRequestReservation(reservationId), responseFn(onResponse), errorFn(errorFn), hasErrorFn(true) + { + } + RequestReservation(int reservationId, ResponseFn onResponse) + : IRequestReservation(reservationId), responseFn(onResponse), hasErrorFn(false) + { + } + }; + std::mutex requestMutex; + std::vector requestReservations; + std::atomic nextRequestId{1}; + +public: + template + void Request(const char *message, const T &body, + std::function onSuccess, + std::function onError) + { + try + { + RequestReservation *reservation = new RequestReservation( + (int)++nextRequestId, + onSuccess, + onError); + { + std::lock_guard lock(requestMutex); + requestReservations.push_back(reservation); + } + std::stringstream s(ios_base::out); + + json_writer writer(s, true); + writer.start_array(); + { + writer.start_object(); + { + writer.write_member("replyTo", reservation->GetReservationid()); + writer.write_raw(","); + writer.write_member("message", message); + } + writer.end_object(); + writer.write_raw(","); + writer.write(body); + } + writer.end_array(); + { + std::lock_guard guard(this->writeMutex); + this->send(s.str()); + } + } + catch (const std::exception &e) + { + onError(PiPedalException(e.what())); + } + } + + template + void Send(const char *message, const T &body) + { + Reply(-1, message, body); + } + void Send(const char *message) + { + Reply(-1, message); + } + + void SendError(int replyTo, std::exception &e) + { + Reply(replyTo, "error", e.what()); + } + void SendError(int replyTo, const std::string &what) + { + Reply(replyTo, "error", what); + } + + bool waitingForPortMonitorAck(uint64_t subscriptionId) + { + { + std::lock_guard guard(subscriptionMutex); + for (int i = 0; i < this->activePortMonitors.size(); ++i) + { + auto &portMonitor = activePortMonitors[i]; + if (portMonitor.subscriptionHandle == subscriptionId) + { + if (portMonitor.waitingForAck) + return true; + portMonitor.waitingForAck = true; + return false; + } + } + } + return true; // subscription has been closed. don't sent to client. + } + void portMonitorAck(uint64_t subscriptionId) + { + { + std::lock_guard guard(subscriptionMutex); + for (int i = 0; i < this->activePortMonitors.size(); ++i) + { + auto &portMonitor = activePortMonitors[i]; + if (portMonitor.subscriptionHandle == subscriptionId) + { + portMonitor.waitingForAck = false; + break; + } + } + } + } + + void handleMessage(int reply, int replyTo, const std::string &message, json_reader *pReader) + { + if (reply != -1) + { + IRequestReservation *reservation = nullptr; + { + std::lock_guard guard(this->requestMutex); + for (auto i = this->requestReservations.begin(); i != this->requestReservations.end(); ++i) + { + if ((*i)->GetReservationid() == reply) + { + reservation = (*i); + requestReservations.erase(i); + break; + } + } + } + // be careful not to take down the whole server because of a client that's shutting down. + if (reservation != nullptr) + { + try + { + reservation->onResult(pReader); + } + catch (const std::exception &e) + { + Lv2Log::error("Socket: Invalid reply '%s'. (%s)", message.c_str(), e.what()); + } + delete reservation; + } + else + { + Lv2Log::warning("Socket: Reply '%s' with nobody waiting.", message.c_str()); + } + return; + } + if (message == "previewControl") + { + ControlChangedBody message; + pReader->read(&message); + this->model.previewControl(message.clientId_, message.instanceId_, message.symbol_, message.value_); + } + else if (message == "setControl") + { + ControlChangedBody message; + pReader->read(&message); + this->model.setControl(message.clientId_, message.instanceId_, message.symbol_, message.value_); + } + else if (message == "listenForMidiEvent") + { + ListenForMidiEventBody body; + pReader->read(&body); + this->model.listenForMidiEvent(this->clientId,body.handle_, body.listenForControlsOnly_); + } + else if (message == "cancelListenForMidiEvent") + { + uint64_t handle; + pReader->read(&handle); + this->model.cancelListenForMidiEvent(this->clientId,handle); + } + else if (message == "getJackStatus") + { + JackHostStatus status = model.getJackStatus(); + this->Reply(replyTo,"getJackStatus",status); + } + else if (message == "getPluginPresets") + { + std::string uri; + pReader->read(&uri); + this->Reply(replyTo,"getPluginPresets",this->model.GetPluginPresets(uri)); + } + else if (message == "loadPluginPreset") + { + LoadPluginPresetBody body; + pReader->read(&body); + this->model.LoadPluginPreset(body.instanceId_,body.presetName_); + + } + else if (message == "setJackServerSettings") { + JackServerSettings jackServerSettings; + pReader->read(&jackServerSettings); + this->model.SetJackServerSettings(jackServerSettings); + this->Reply(replyTo,"setJackserverSettings"); + + } + else if (message == "getJackServerSettings") { + this->Reply(replyTo, "getJackServerSettings", model.GetJackServerSettings()); + + } + else if (message == "getBankIndex") { + BankIndex bankIndex = model.getBankIndex(); + this->Reply(replyTo, "getBankIndex", bankIndex); + + } + else if (message == "getJackConfiguration") + { + JackConfiguration configuration = this->model.getJackConfiguration(); + this->Reply(replyTo, "getJackConfiguration", configuration); + } + else if (message == "getJackSettings") + { + JackChannelSelection selection = this->model.getJackChannelSelection(); + this->Reply(replyTo, "getJackSettings", selection); + } + else if (message == "saveCurrentPreset") + { + this->model.saveCurrentPreset(this->clientId); + } + else if (message == "saveCurrentPresetAs") + { + SaveCurrentPresetAsBody body; + pReader->read(&body); + int64_t result = this->model.saveCurrentPresetAs(this->clientId, body.name_, body.saveAfterInstanceId_); + Reply(replyTo, "saveCurrentPresetsAs", result); + } + else if (message == "getPresets") + { + PresetIndex presets; + this->model.getPresets(&presets); + Reply(replyTo, "getPresets", presets); + } + else if (message == "setPedalBoardItemEnable") + { + PedalBoardItemEnabledBody body; + pReader->read(&body); + model.setPedalBoardItemEnable(body.clientId_, body.instanceId_, body.enabled_); + } + else if (message == "setCurrentPedalBoard") + { + { + SetCurrentPedalBoardBody body; + + pReader->read(&body); + this->model.setPedalBoard(body.clientId_, body.pedalBoard_); + } + } + else if (message == "currentPedalBoard") + { + auto pedalBoard = model.getCurrentPedalBoardCopy(); + Reply(replyTo, "currentPedalBoard", pedalBoard); + } + else if (message == "plugins") + { + auto ui_plugins = model.getPlugins().GetUiPlugins(); + Reply(replyTo, "plugins", ui_plugins); + } + else if (message == "pluginClasses") + { + auto classes = model.getPlugins().GetLv2PluginClass(); + Reply(replyTo, "pluginClasses", classes); + } + else if (message == "hello") + { + this->model.AddNotificationSubscription(this); + Reply(replyTo, "ehlo", clientId); + } + else if (message == "setJackSettings") + { + JackChannelSelection jackSettings; + pReader->read(&jackSettings); + this->model.setJackChannelSelection(this->clientId, jackSettings); + } + else if (message == "version") + { + PiPedalVersion version; + + Reply(replyTo, "version", version); + } + else if (message == "loadPreset") + { + int64_t instanceId = 0; + pReader->read(&instanceId); + model.loadPreset(this->clientId, instanceId); + } + else if (message == "updatePresets") + { + PresetIndex newIndex; + pReader->read(&newIndex); + bool result = model.updatePresets(this->clientId, newIndex); + this->Reply(replyTo, "updatePresets", result); + } + else if (message == "moveBank") + { + FromToBody body; + pReader->read(&body); + model.moveBank(this->clientId, body.from_, body.to_); + this->Reply(replyTo, "moveBank"); + } + else if (message == "shutdown") + { + PresetIndex newIndex; + + requestShutdown(false); + this->Reply(replyTo,"shutdown"); + } + else if (message == "restart") + { + PresetIndex newIndex; + requestShutdown(true); + this->Reply(replyTo,"restart"); + } + else if (message == "deletePresetItem") + { + int64_t instanceId = 0; + pReader->read(&instanceId); + int64_t result = model.deletePreset(this->clientId, instanceId); + this->Reply(replyTo, "deletePresetItem", result); + } + else if (message == "deleteBankItem") + { + int64_t instanceId = 0; + pReader->read(&instanceId); + uint64_t result = model.deleteBank(this->clientId, instanceId); + this->Reply(replyTo, "deleteBankItem", result); + } + else if (message == "renameBank") + { + RenameBankBody body; + pReader->read(&body); + + std::stringstream tOut; + json_writer tWriter(tOut); + tWriter.write(body.newName_); + std::string tJson = tOut.str(); + std::stringstream tIn(tJson); + json_reader tReader(tIn); + std::string tResult; + tReader.read(&tResult); + + body.newName_ = tResult; + + + try { + model.renameBank(this->clientId,body.bankId_, body.newName_); + this->Reply(replyTo, "renameBank"); + } catch (const std::exception &e) + { + this->SendError(replyTo,std::string(e.what())); + } + } + else if (message == "openBank") + { + int64_t bankId = -1; + pReader->read(&bankId); + try { + model.openBank(this->clientId,bankId);; + this->Reply(replyTo, "openBank"); + } catch (const std::exception &e) + { + this->SendError(replyTo,std::string(e.what())); + } + } + else if (message == "saveBankAs") + { + RenameBankBody body; + pReader->read(&body); + try { + int64_t newId = model.saveBankAs(this->clientId,body.bankId_, body.newName_); + this->Reply(replyTo, "saveBankAs",newId); + } catch (const std::exception &e) + { + this->SendError(replyTo,std::string(e.what())); + } + } + else if (message == "renamePresetItem") + { + RenamePresetBody body; + pReader->read(&body); + + bool result = model.renamePreset(body.clientId_, body.instanceId_, body.name_); + this->Reply(replyTo, "renamePresetItem", result); + } + else if (message == "copyPreset") + { + CopyPresetBody body; + pReader->read(&body); + int64_t result = model.copyPreset(body.clientId_, body.fromId_, body.toId_); + this->Reply(replyTo, "copyPreset", result); + } + else if (message =="getLv2Parameter") + { + GetLv2ParameterBody body; + pReader->read(&body); + + model.getLv2Parameter( + this->clientId, + body.instanceId_, + body.uri_, + [this,replyTo] (const std::string &jsonResult) + { + this->JsonReply(replyTo,"getLv2Parameter",jsonResult.c_str()); + }, + [this,replyTo] (const std::string &error) { + this->SendError(replyTo,error.c_str()); + }); + + } + else if (message == "monitorPort") + { + + MonitorPortBody body; + pReader->read(&body); + + int64_t subscriptionHandle = model.monitorPort( + body.instanceId_, + body.key_, + body.updateRate_, + [this](int64_t subscriptionHandle_, float value) + { + MonitorResultBody body; + body.subscriptionHandle_ = subscriptionHandle_; + body.value_ = value; + if (!waitingForPortMonitorAck(subscriptionHandle_)) //only one outstanding response. + { + this->Request( // send the message and wait for a response. + "onMonitorPortOutput", + body, + [this, subscriptionHandle_](const bool &result) + { + this->portMonitorAck(subscriptionHandle_); // please can we have some more. + // (....complexity not worth the effort. :-( ) + }, + [](const std::exception &e) + { + Lv2Log::debug("Failed to monitor port output. (%s)", e.what()); + }); + } + }); + { + std::lock_guard guard(subscriptionMutex); + activePortMonitors.push_back( + PortMonitorSubscription{subscriptionHandle, body.instanceId_,false, body.key_}); + } + + this->Reply(replyTo, "monitorPort", subscriptionHandle); + } + else if (message == "unmonitorPort") + { + int64_t subscriptionHandle; + pReader->read(&subscriptionHandle); + { + { + std::lock_guard guard(subscriptionMutex); + for (auto i = this->activePortMonitors.begin(); i != this->activePortMonitors.end(); ++i) + { + if ((*i).subscriptionHandle == subscriptionHandle) + { + this->activePortMonitors.erase(i); + break; + } + } + } + model.unmonitorPort(subscriptionHandle); + } + } + else if (message == "addVuSubscription") + { + int64_t instanceId = -1; + + pReader->read(&instanceId); + + int64_t subscriptionHandle = model.addVuSubscription(instanceId); + + { + std::lock_guard guard(subscriptionMutex); + activeVuSubscriptions.push_back(VuSubscription{subscriptionHandle, instanceId}); + } + this->Reply(replyTo, "addVuSubscriptin", subscriptionHandle); + } + else if (message == "removeVuSubscription") + { + int64_t subscriptionHandle = -1; + pReader->read(&subscriptionHandle); + { + std::lock_guard guard(subscriptionMutex); + + for (auto i = activeVuSubscriptions.begin(); i != activeVuSubscriptions.end(); ++i) + { + if (i->subscriptionHandle == subscriptionHandle) + { + activeVuSubscriptions.erase(i); + break; + } + } + } + model.removeVuSubscription(subscriptionHandle); + } + else + { + Lv2Log::error("Unknown message received: %s", message.c_str()); + SendError(replyTo, std::string("Unknown message: ") + message); + } + } + +protected: + virtual void + onReceive(const std::string_view &text) + { + view_istream s(text); + + json_reader reader(s); + // read top level object until we have message + int64_t replyTo = -1; + int64_t reply = -1; + std::string message; + + try + { + reader.consume('['); + reader.consume('{'); + + while (true) + { + if (reader.peek() == '}') + { + reader.consume('}'); + break; + } + std::string name = reader.read_string(); + reader.consume(':'); + if (name == "reply") + { + reader.read(&reply); + } + if (name == "replyTo") + { + reader.read(&replyTo); + } + if (name == "message") + { + message = reader.read_string(); + } + if (reader.peek() == ',') + { + reader.consume(','); + continue; + } + } + if (reader.peek() == ',') + { + reader.consume(','); + handleMessage(reply, replyTo, message, &reader); + } + else + { + handleMessage(reply, replyTo, message, nullptr); + } + // Handle message. + } + catch (const PiPedalException &e) + { + SendError(replyTo, e.what()); + } + catch (const std::exception & e) + { + SendError(replyTo, e.what()); + } + } + +public: + virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection &channelSelection) + { + ChannelSelectionChangedBody body; + body.clientId_ = clientId; + body.jackChannelSelection_ = const_cast(&channelSelection); + Send("onChannelSelectionChanged", body); + } + virtual void OnPresetsChanged(int64_t clientId, const PresetIndex &presets) + { + PresetsChangedBody body; + body.clientId_ = clientId; + body.presets_ = const_cast(&presets); + Send("onPresetsChanged", body); + } + virtual void OnJackConfigurationChanged(const JackConfiguration &jackConfiguration) + { + Send("onJackConfigurationChanged", jackConfiguration); + } + + virtual void OnLoadPluginPreset(int64_t instanceId,const std::vector&controlValues) { + OnLoadPluginPresetBody body; + body.instanceId_ = instanceId; + body.controlValues_ = const_cast&>(controlValues); + Send("onLoadPluginPreset",body); + } + + + int updateRequestOutstanding = 0; + bool vuUpdateDropped = false; + + virtual void OnVuMeterUpdate(const std::vector &updates) + { + std::lock_guard guard(subscriptionMutex); + if (updateRequestOutstanding < 5) // throttle to accomodate a web page that can't keep up. + { + vuUpdateDropped = false; + for (int i = 0; i < updates.size(); ++i) + { + const VuUpdate &vuUpdate = updates[i]; + bool interested = false; + for (int i = 0; i < this->activeVuSubscriptions.size(); ++i) + { + if (activeVuSubscriptions[i].instanceId == vuUpdate.instanceId_) + { + interested = true; + break; + } + } + if (interested) + { + updateRequestOutstanding++; + this->Request( + "onVuUpdate", + vuUpdate, + [this](const bool &result) + { + this->updateRequestOutstanding--; + }, + [this](const std::exception &) + { + this->updateRequestOutstanding--; + }); + } + } + } + else + { + if (!vuUpdateDropped) + { + vuUpdateDropped = true; + Lv2Log::debug("Vu Update(s) dropped."); + } + } + } + + virtual void OnControlChanged(int64_t clientId, int64_t instanceId, const std::string &key, float value) + { + ControlChangedBody body; + body.clientId_ = clientId; + body.instanceId_ = instanceId; + body.symbol_ = key; + body.value_ = value; + Send("onControlChanged", body); + } + + class DeferredValue { + public: + int64_t instanceId; + std::string symbol; + float value; + }; + + std::vector deferredValues; + bool midiValueChangedOutstanding = false; + + + virtual void OnMidiValueChanged(int64_t instanceId, const std::string&symbol, float value) { + if (midiValueChangedOutstanding) + { + for (size_t i = 0; i < deferredValues.size(); ++i) { + auto &deferredValue = deferredValues[i]; + if (deferredValue.instanceId == instanceId && deferredValue.symbol == symbol) + { + deferredValue.value = value; + return; + } + } + DeferredValue newValue {instanceId,symbol,value}; + deferredValues.push_back(newValue); + } else { + midiValueChangedOutstanding = true; + ControlChangedBody body; + body.clientId_ = -1; + body.instanceId_ = instanceId; + body.symbol_ = symbol; + body.value_ = value; + Request("onMidiValueChanged", body, + [this] (const bool& value) + { + this->midiValueChangedOutstanding = false; + if (this->deferredValues.size() != 0) + { + DeferredValue value = deferredValues[0]; + deferredValues.erase(deferredValues.begin()); + this->OnMidiValueChanged(value.instanceId,value.symbol,value.value); + } + + }, + [] (const std::exception &e) { + + } + ); + } + } + + virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) + { + NotifyMidiListenerBody body; + body.clientHandle_ = clientHandle; + body.isNote_ = isNote; + body.noteOrControl_ = noteOrControl; + + Send("onNotifyMidiListener",body); + } + + + + virtual void OnBankIndexChanged(const BankIndex& bankIndex) + { + Send("onBanksChanged",bankIndex); + } + + virtual void OnJackServerSettingsChanged(const JackServerSettings& jackServerSettings) + { + Send("onJackServerSettingsChanged",jackServerSettings); + } + + virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard) + { + SetCurrentPedalBoardBody body; + body.clientId_ = clientId; + body.pedalBoard_ = pedalBoard; + Send("onPedalBoardChanged", body); + } + + + virtual void OnItemEnabledChanged(int64_t clientId, int64_t pedalItemId, bool enabled) + { + PedalBoardItemEnabledBody body; + body.clientId_ = clientId; + body.instanceId_ = pedalItemId; + body.enabled_ = enabled; + Send("onItemEnabledChanged", body); + } +}; + +std::atomic PiPedalSocketHandler::nextClientId = 0; + +class PiPedalSocketFactory : public ISocketFactory +{ +private: + PiPedalModel &model; + +public: + virtual ~PiPedalSocketFactory() + { + } + PiPedalSocketFactory(PiPedalModel &model) + : model(model) + { + } + +public: + virtual bool wants(const uri &request) + { + if (request.segment(0) == "pipedal") + return true; + return false; + } + virtual std::shared_ptr CreateHandler(const uri &request) + { + return std::make_shared(model); + } +}; + +std::shared_ptr pipedal::MakePiPedalSocketFactory(PiPedalModel &model) +{ + return std::make_shared(model); +} + diff --git a/src/PiPedalSocket.hpp b/src/PiPedalSocket.hpp new file mode 100644 index 0000000..c27d866 --- /dev/null +++ b/src/PiPedalSocket.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "BeastServer.hpp" +#include "PiPedalModel.hpp" + + +namespace pipedal { + + std::shared_ptr MakePiPedalSocketFactory(PiPedalModel &model); +}; + diff --git a/src/PiPedalVersion.cpp b/src/PiPedalVersion.cpp new file mode 100644 index 0000000..50babb5 --- /dev/null +++ b/src/PiPedalVersion.cpp @@ -0,0 +1,55 @@ +#include "pch.h" +#include "config.hpp" +#include "PiPedalVersion.hpp" + +#ifdef _WIN32 +#include "windows.h" +#include "sstream" +#else +#include +#endif + +using namespace pipedal; + +JSON_MAP_BEGIN(PiPedalVersion) + JSON_MAP_REFERENCE(PiPedalVersion,server) + JSON_MAP_REFERENCE(PiPedalVersion,serverVersion) + JSON_MAP_REFERENCE(PiPedalVersion,operatingSystem) + JSON_MAP_REFERENCE(PiPedalVersion,osVersion) + JSON_MAP_REFERENCE(PiPedalVersion,debug) +JSON_MAP_END() + +PiPedalVersion::PiPedalVersion() +{ + server_ = "PiPedal Server"; + // defined on build command line. + serverVersion_ = PROJECT_VER; +#ifdef _WIN32 + OSVERSIONINFOEXA info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEA)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEA); + + GetVersionExA(&info); + + ::stringstream s; + s << info.dwMajorVersion << '.' << info.dwMinorVersion << '.' << info.dwBuildNumber; + #ifdef _WIN32 + operatingSystem_ = "Windows 32-bit"; + #elif _WIN64 + operatingSystem_ = "Windows 64-bit"; + #endif + osVersion_ = s.str(); +#else + struct utsname uts; + uname(&uts); + operatingSystem_ = uts.sysname; + + osVersion_ = std::string(uts.release) + "/"+ std::string(uts.machine); +#endif + +#ifdef DEBUG + debug_ = true; +#else + debug_ = false; +#endif +} diff --git a/src/PiPedalVersion.hpp b/src/PiPedalVersion.hpp new file mode 100644 index 0000000..043b3ec --- /dev/null +++ b/src/PiPedalVersion.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "json.hpp" + +namespace pipedal { + +class PiPedalVersion { +private: + std::string server_; + std::string serverVersion_; + std::string operatingSystem_; + std::string osVersion_; + bool debug_; + +public: + PiPedalVersion(); + ~PiPedalVersion() = default; + + + DECLARE_JSON_MAP(PiPedalVersion); +}; + +} // namepace pipedal \ No newline at end of file diff --git a/src/PluginType.cpp b/src/PluginType.cpp new file mode 100644 index 0000000..0d50d4f --- /dev/null +++ b/src/PluginType.cpp @@ -0,0 +1,189 @@ +#include "pch.h" +#include +#include "PluginType.hpp" + + + +using namespace pipedal; + + +class PluginTypeMapEntry { +public: + PluginType pedal_type; + const std::string uri; +}; + + +#define CORE_URI_PREFIX "http://lv2plug.in/ns/lv2core#" + +#define URI_TO_TYPE_MAP_ENTRY(TYPE) \ + {std::string(CORE_URI_PREFIX #TYPE),PluginType::TYPE } + +static std::pair urisToNames[] { + { "", PluginType::None}, + URI_TO_TYPE_MAP_ENTRY(EmptyPlugin), + URI_TO_TYPE_MAP_ENTRY(SplitterPlugin), + URI_TO_TYPE_MAP_ENTRY(Plugin), + URI_TO_TYPE_MAP_ENTRY(InvalidPlugin), + URI_TO_TYPE_MAP_ENTRY(Plugin), + URI_TO_TYPE_MAP_ENTRY(AllpassPlugin), + URI_TO_TYPE_MAP_ENTRY(AmplifierPlugin), + URI_TO_TYPE_MAP_ENTRY(AnalyserPlugin), + URI_TO_TYPE_MAP_ENTRY(BandpassPlugin), + URI_TO_TYPE_MAP_ENTRY(ChorusPlugin), + URI_TO_TYPE_MAP_ENTRY(CombPlugin), + URI_TO_TYPE_MAP_ENTRY(CompressorPlugin), + URI_TO_TYPE_MAP_ENTRY(ConstantPlugin), + URI_TO_TYPE_MAP_ENTRY(ConverterPlugin), + URI_TO_TYPE_MAP_ENTRY(DelayPlugin), + URI_TO_TYPE_MAP_ENTRY(DistortionPlugin), + URI_TO_TYPE_MAP_ENTRY(DynamicsPlugin), + URI_TO_TYPE_MAP_ENTRY(EQPlugin), + URI_TO_TYPE_MAP_ENTRY(EnvelopePlugin), + URI_TO_TYPE_MAP_ENTRY(ExpanderPlugin), + URI_TO_TYPE_MAP_ENTRY(FilterPlugin), + URI_TO_TYPE_MAP_ENTRY(FlangerPlugin), + URI_TO_TYPE_MAP_ENTRY(FunctionPlugin), + URI_TO_TYPE_MAP_ENTRY(GatePlugin), + URI_TO_TYPE_MAP_ENTRY(GeneratorPlugin), + URI_TO_TYPE_MAP_ENTRY(HighpassPlugin), + URI_TO_TYPE_MAP_ENTRY(InstrumentPlugin), + URI_TO_TYPE_MAP_ENTRY(LimiterPlugin), + URI_TO_TYPE_MAP_ENTRY(LowpassPlugin), + URI_TO_TYPE_MAP_ENTRY(MixerPlugin), + URI_TO_TYPE_MAP_ENTRY(ModulatorPlugin), + URI_TO_TYPE_MAP_ENTRY(MultiEQPlugin), + URI_TO_TYPE_MAP_ENTRY(OscillatorPlugin), + URI_TO_TYPE_MAP_ENTRY(ParaEQPlugin), + URI_TO_TYPE_MAP_ENTRY(PhaserPlugin), + URI_TO_TYPE_MAP_ENTRY(PitchPlugin), + URI_TO_TYPE_MAP_ENTRY(ReverbPlugin), + URI_TO_TYPE_MAP_ENTRY(SimulatorPlugin), + URI_TO_TYPE_MAP_ENTRY(SpatialPlugin), + URI_TO_TYPE_MAP_ENTRY(SpectralPlugin), + URI_TO_TYPE_MAP_ENTRY(UtilityPlugin), + URI_TO_TYPE_MAP_ENTRY(WaveshaperPlugin), + URI_TO_TYPE_MAP_ENTRY(MIDIPlugin), +}; + +PluginType pipedal::uri_to_plugin_type(const std::string&uri) +{ + for (auto& i: urisToNames) + { + if (i.first == uri) + { + return i.second; + } + } + return PluginType::None; +} + + +const std::string& pipedal::plugin_type_to_uri(PluginType type) +{ + for (auto& i: urisToNames) + { + if (i.second == type) + { + return i.first; + } + } + throw std::invalid_argument("Plugin type not valid."); +} + +#define STRING_TO_TYPE_MAP_ENTRY(TYPE) \ + {std::string(#TYPE),PluginType::TYPE } + +static std::pair strings_to_type_map[] { + { "", PluginType::None}, + STRING_TO_TYPE_MAP_ENTRY(InvalidPlugin), + STRING_TO_TYPE_MAP_ENTRY(Plugin), + STRING_TO_TYPE_MAP_ENTRY(AllpassPlugin), + STRING_TO_TYPE_MAP_ENTRY(AmplifierPlugin), + STRING_TO_TYPE_MAP_ENTRY(AnalyserPlugin), + STRING_TO_TYPE_MAP_ENTRY(BandpassPlugin), + STRING_TO_TYPE_MAP_ENTRY(ChorusPlugin), + STRING_TO_TYPE_MAP_ENTRY(CombPlugin), + STRING_TO_TYPE_MAP_ENTRY(CompressorPlugin), + STRING_TO_TYPE_MAP_ENTRY(ConstantPlugin), + STRING_TO_TYPE_MAP_ENTRY(ConverterPlugin), + STRING_TO_TYPE_MAP_ENTRY(DelayPlugin), + STRING_TO_TYPE_MAP_ENTRY(DistortionPlugin), + STRING_TO_TYPE_MAP_ENTRY(DynamicsPlugin), + STRING_TO_TYPE_MAP_ENTRY(EQPlugin), + STRING_TO_TYPE_MAP_ENTRY(EnvelopePlugin), + STRING_TO_TYPE_MAP_ENTRY(ExpanderPlugin), + STRING_TO_TYPE_MAP_ENTRY(FilterPlugin), + STRING_TO_TYPE_MAP_ENTRY(FlangerPlugin), + STRING_TO_TYPE_MAP_ENTRY(FunctionPlugin), + STRING_TO_TYPE_MAP_ENTRY(GatePlugin), + STRING_TO_TYPE_MAP_ENTRY(GeneratorPlugin), + STRING_TO_TYPE_MAP_ENTRY(HighpassPlugin), + STRING_TO_TYPE_MAP_ENTRY(InstrumentPlugin), + STRING_TO_TYPE_MAP_ENTRY(LimiterPlugin), + STRING_TO_TYPE_MAP_ENTRY(LowpassPlugin), + STRING_TO_TYPE_MAP_ENTRY(MixerPlugin), + STRING_TO_TYPE_MAP_ENTRY(ModulatorPlugin), + STRING_TO_TYPE_MAP_ENTRY(MultiEQPlugin), + STRING_TO_TYPE_MAP_ENTRY(OscillatorPlugin), + STRING_TO_TYPE_MAP_ENTRY(ParaEQPlugin), + STRING_TO_TYPE_MAP_ENTRY(PhaserPlugin), + STRING_TO_TYPE_MAP_ENTRY(PitchPlugin), + STRING_TO_TYPE_MAP_ENTRY(ReverbPlugin), + STRING_TO_TYPE_MAP_ENTRY(SimulatorPlugin), + STRING_TO_TYPE_MAP_ENTRY(SpatialPlugin), + STRING_TO_TYPE_MAP_ENTRY(SpectralPlugin), + STRING_TO_TYPE_MAP_ENTRY(UtilityPlugin), + STRING_TO_TYPE_MAP_ENTRY(WaveshaperPlugin), + STRING_TO_TYPE_MAP_ENTRY(MIDIPlugin), +}; + +PluginType pipedal::string_to_plugin_type(const std::string&uri) +{ + for (auto& i: strings_to_type_map) + { + if (i.first == uri) + { + return i.second; + } + } + return PluginType::None; +} + + +const std::string &pipedal::plugin_type_to_string(PluginType type) +{ + for (auto& i: strings_to_type_map) + { + if (i.second == type) + { + return i.first; + } + } + throw std::invalid_argument("Plugin type not valid."); + +} + + + + +class PluginTypeEnumConverter: public json_enum_converter { +public: + virtual PluginType fromString(const std::string&value) const + { + return string_to_plugin_type(value); + } + virtual const std::string& toString(PluginType value) const + { + return plugin_type_to_string(value); + } + + +} g_plugin_type_converter; + + +json_enum_converter *pipedal::get_plugin_type_enum_converter() +{ + return &g_plugin_type_converter; +} + diff --git a/src/PluginType.hpp b/src/PluginType.hpp new file mode 100644 index 0000000..319aa58 --- /dev/null +++ b/src/PluginType.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include "json.hpp" + + +namespace pipedal { + +enum class PluginType { + None, + + EmptyPlugin, // Pedalboards only. + SplitterPlugin, // Pedalboards only. + + InvalidPlugin, + Plugin, + AllpassPlugin, + AmplifierPlugin, + AnalyserPlugin, + BandpassPlugin, + ChorusPlugin, + CombPlugin, + CompressorPlugin, + ConstantPlugin, + ConverterPlugin, + DelayPlugin, + DistortionPlugin, + DynamicsPlugin, + EQPlugin, + EnvelopePlugin, + ExpanderPlugin, + FilterPlugin, + FlangerPlugin, + FunctionPlugin, + GatePlugin, + GeneratorPlugin, + HighpassPlugin, + InstrumentPlugin, + LimiterPlugin, + LowpassPlugin, + MixerPlugin, + ModulatorPlugin, + MultiEQPlugin, + OscillatorPlugin, + ParaEQPlugin, + PhaserPlugin, + PitchPlugin, + ReverbPlugin, + SimulatorPlugin, + SpatialPlugin, + SpectralPlugin, + UtilityPlugin, + WaveshaperPlugin, + MIDIPlugin, +}; + +const std::string &plugin_type_to_uri(PluginType type); +PluginType uri_to_plugin_type(const std::string&uri); + +PluginType string_to_plugin_type(const std::string&value); +const std::string& plugin_type_to_string(PluginType value); + + +json_enum_converter *get_plugin_type_enum_converter(); + + +}; // namespace pipedal. \ No newline at end of file diff --git a/src/Presets.cpp b/src/Presets.cpp new file mode 100644 index 0000000..b108f2f --- /dev/null +++ b/src/Presets.cpp @@ -0,0 +1,25 @@ +#include "pch.h" +#include "Presets.hpp" + +using namespace pipedal; + +JSON_MAP_BEGIN(PedalPreset) + JSON_MAP_REFERENCE(PedalPreset,instanceId) + JSON_MAP_REFERENCE(PedalPreset,values) +JSON_MAP_END() + +JSON_MAP_BEGIN(PedalBoardPreset) + JSON_MAP_REFERENCE(PedalBoardPreset,instanceId) + JSON_MAP_REFERENCE(PedalBoardPreset,displayName) + JSON_MAP_REFERENCE(PedalBoardPreset,values) +JSON_MAP_END() + + +JSON_MAP_BEGIN(PedalBoardPresets) + JSON_MAP_REFERENCE(PedalBoardPresets,nextInstanceId) + JSON_MAP_REFERENCE(PedalBoardPresets,currentPreset) + JSON_MAP_REFERENCE(PedalBoardPresets,presets) +JSON_MAP_END() + + + diff --git a/src/Presets.hpp b/src/Presets.hpp new file mode 100644 index 0000000..851fe50 --- /dev/null +++ b/src/Presets.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "PedalBoard.hpp" +#include "json.hpp" + +namespace pipedal { + +class PedalPreset { +private: + int instanceId_ = -1; + std::vector values_; +public: + DECLARE_JSON_MAP(PedalPreset); +}; + +class PedalBoardPreset { + long instanceId_; + std::string displayName_; + std::vector > values_; +public: + DECLARE_JSON_MAP(PedalBoardPreset); +}; + +class PedalBoardPresets { + long nextInstanceId_ = 0; + + long currentPreset_ = 0; + std::vector > presets_; +public: + DECLARE_JSON_MAP(PedalBoardPresets); + +}; + +} // namespace. \ No newline at end of file diff --git a/src/RequestHandler.hpp b/src/RequestHandler.hpp new file mode 100644 index 0000000..54ee933 --- /dev/null +++ b/src/RequestHandler.hpp @@ -0,0 +1,6 @@ +#pragma once + + + + + diff --git a/src/RingBuffer.hpp b/src/RingBuffer.hpp new file mode 100644 index 0000000..2736254 --- /dev/null +++ b/src/RingBuffer.hpp @@ -0,0 +1,176 @@ +#pragma once +#include +#include "PiPedalException.hpp" +#include +#include +#include + + +#ifndef NO_MLOCK +#include +#endif /* NO_MLOCK */ + + +namespace pipedal +{ + template + class RingBuffer { + char *buffer; + bool mlocked = false; + size_t ringBufferSize; + size_t ringBufferMask; + volatile int64_t readPosition = 0; // volatile = ordering barrier wrt writePosition + volatile int64_t writePosition = 0; // volatile = ordering barrier wrt/ readPosition + std::mutex write_mutex; + + sem_t readSemaphore; + bool semaphore_open = false; + + size_t nextPowerOfTwo(size_t size) + { + size_t v = 1; + while (v < size) + { + v *= 2; + } + return v; + } + public: + RingBuffer(size_t ringBufferSize = 65536, bool mLock = true) + { + this->ringBufferSize = ringBufferSize = nextPowerOfTwo(ringBufferSize); + ringBufferMask = ringBufferSize-1; + buffer = new char[ringBufferSize]; + + if (SEMAPHORE_READER) { + sem_init(&readSemaphore,0,0); + semaphore_open = true; + } + + #ifndef NO_MLOCK + if (mLock) + { + if (mlock (buffer, ringBufferSize)) { + throw PiPedalStateException("Mlock failed."); + } + this->mlocked = true; + } + #endif + } + + void reset() { + this->readPosition = 0; + this->writePosition = 0; + if (SEMAPHORE_READER) + { + sem_destroy(&readSemaphore); + sem_init(&readSemaphore,0,0); + this->semaphore_open = true; + } + } + void close() { + if (SEMAPHORE_READER) + { + this->semaphore_open = false; + sem_post(&readSemaphore); + } + } + // 0 -> ready. -1: timed out. -2: closing. + int readWait(const struct timespec& timeoutMs) { + if (SEMAPHORE_READER) + { + int result = sem_timedwait(&readSemaphore,&timeoutMs); + if (!semaphore_open) return -2; + return (result == 0) ? 0: -1; + } else { + throw PiPedalStateException("SEMAPHORE_READER is not set to true."); + } + } + + bool readWait() { + if (SEMAPHORE_READER) + { + sem_wait(&readSemaphore); + return semaphore_open; + } else { + throw PiPedalStateException("SEMAPHORE_READER is not set to true."); + } + } + size_t writeSpace() { + // at most ringBufferSize-1 in order to + // to distinguish the empty buffer from the full buffer. + int64_t size = readPosition-1-writePosition; + if (size < 0) size += this->ringBufferSize; + return (size_t)size; + } + size_t readSpace() { + int64_t size = writePosition-readPosition; + if (size < 0) size += this->ringBufferSize; + return size_t(size); + } + bool write(size_t bytes, uint8_t *data) + { + if (MULTI_WRITER) + { + std::lock_guard guard(write_mutex); + if (writeSpace() < bytes) { + return false; + } + size_t index = this->writePosition; + for (size_t i = 0; i < bytes; ++i) + { + buffer[(index+i) & ringBufferMask] = data[i]; + } + this->writePosition = (index+bytes) & ringBufferMask; + if (SEMAPHORE_READER) + { + sem_post(&readSemaphore); + } + return true; + } else { + if (writeSpace() < bytes) { + return false; + } + size_t index = this->writePosition; + for (size_t i = 0; i < bytes; ++i) + { + buffer[(index+i) & ringBufferMask] = data[i]; + } + this->writePosition = (index+bytes) & ringBufferMask; + if (SEMAPHORE_READER) + { + sem_post(&readSemaphore); + } + return true; + } + } + bool read(size_t bytes, uint8_t*data) + { + if (readSpace() < bytes) return false; + int64_t readPosition = this->readPosition; + for (size_t i = 0; i < bytes; ++i) + { + data[i] = this->buffer[(readPosition+i) & this->ringBufferMask]; + } + this->readPosition = (readPosition + bytes) & this->ringBufferMask; + return true; + } + ~RingBuffer() + { + #ifdef USE_MLOCK + if (this->mlocked) + { + munlock(buffer,ringBufferSize); + } + #endif + if (SEMAPHORE_READER) + { + sem_destroy(&this->readSemaphore); + } + + delete[] buffer; + } + }; + +}; + diff --git a/src/RingBufferReader.hpp b/src/RingBufferReader.hpp new file mode 100644 index 0000000..751091f --- /dev/null +++ b/src/RingBufferReader.hpp @@ -0,0 +1,338 @@ +#pragma once + +#include "PiPedalException.hpp" +#include "Lv2Log.hpp" +#include "VuUpdate.hpp" +#include "JackHost.hpp" + +namespace pipedal +{ + + enum class RingBufferCommand : int64_t + { + ReplaceEffect = 0, + EffectReplaced = 1, + SetValue = 2, + SetBypass = 3, + AudioStopped = 4, + SetVuSubscriptions = 5, + FreeVuSubscriptions = 6, + SendVuUpdate = 7, + AckVuUpdate = 8, + + SetMonitorPortSubscription = 9, + FreeMonitorPortSubscription = 10, + SendMonitorPortUpdate = 11, + AckMonitorPortUpdate = 12, + ParameterRequest = 13, + ParameterRequestComplete = 14, + + MidiValueChanged = 15, + + OnMidiListen = 16, + + }; + + class RealtimeMonitorPortSubscription + { + public: + RealtimeMonitorPortSubscription() { delete callbackPtr; } + int64_t subscriptionHandle; + int instanceIndex = 0; + int portIndex = 0; + PortMonitorCallback *callbackPtr = nullptr; + int sampleRate = 0; + int samplesToNextCallback = 0; + bool waitingForAck = false; + }; + + class RealtimeMonitorPortSubscriptions + { + public: + std::vector subscriptions; + }; + + struct RealtimeVuBuffers + { + RealtimeVuBuffers() + { + Reset(); + } + bool waitingForAcknowledge = false; + + const std::vector *GetResult(size_t currentSample) + { + for (size_t i = 0; i < vuUpdateWorkingData.size(); ++i) + { + vuUpdateResponseData[i] = vuUpdateWorkingData[i]; + vuUpdateResponseData[i].sampleTime_ = currentSample; + vuUpdateWorkingData[i].reset(); + } + return &vuUpdateResponseData; + } + + std::vector enabledIndexes; + std::vector vuUpdateWorkingData; + std::vector vuUpdateResponseData; + + void Reset() + { + for (int i = 0; i < vuUpdateWorkingData.size(); ++i) + { + vuUpdateWorkingData[i].reset(); + } + } + }; + + class AudioStoppedBody + { + bool dummy = true; + }; + + class SetBypassBody + { + public: + int effectIndex; + bool enabled; + }; + + class MidiValueChangedBody + { + public: + int64_t instanceId; + int controlIndex; + float value; + }; + + + class SetControlValueBody + { + public: + int effectIndex; + int controlIndex; + float value; + }; + + class Lv2PedalBoard; + + class ReplaceEffectBody + { + public: + Lv2PedalBoard *effect; + }; + class EffectReplacedBody + { + public: + Lv2PedalBoard *oldEffect; + }; + + template + class RingBufferReader + { + + private: + RingBuffer *ringBuffer = nullptr; + + public: + RingBufferReader() + : ringBuffer(nullptr) + { + } + RingBufferReader(RingBuffer *ringBuffer) + : ringBuffer(ringBuffer) + { + } + + // 0 -> ready. -1: timed out. -2: closing. + int wait(struct timespec &timeout) { + return ringBuffer->readWait(timeout); + } + + bool wait() { + return ringBuffer->readWait(); + } + size_t readSpace() const + { + return ringBuffer->readSpace(); + } + template + bool read(T *output) + { + size_t available = readSpace(); + if (available < sizeof(T)) + return false; + if (!ringBuffer->read(sizeof(T),(uint8_t*)output)) + { + throw PiPedalStateException("Ringbuffer read failed. Did you forget to check for space?"); + } + return true; + } + template + void readComplete(T *output) + { + if (!ringBuffer->read(sizeof(T),(uint8_t*)output)) + { + throw PiPedalStateException("Ringbuffer read failed. Did you forget to check for space?"); + } + } + + + + }; + + template + class CommandBuffer + { + + public: + CommandBuffer(RingBufferCommand command) + : command(command) + { + } + + CommandBuffer(RingBufferCommand command, const T &value) + : command(command), value(value) + { + } + RingBufferCommand command; + + size_t size() const { return sizeof(RingBufferCommand) + sizeof(T); } + + T value; + }; + + template + class RingBufferWriter + { + + private: + RingBuffer* ringBuffer; + + public: + RingBufferWriter() + : ringBuffer(nullptr) + { + } + RingBufferWriter(RingBuffer*ringBuffer) + : ringBuffer(ringBuffer) + { + } + + template + void write(RingBufferCommand command, const T &value) + { + + // the goal: to atomically write the command and associated data. + CommandBuffer buffer(command, value); + + if (!ringBuffer->write(buffer.size(),(uint8_t *)&buffer)) + { + Lv2Log::error("No space in audio service ringbuffer."); + return; + + } + } + void ParameterRequest(RealtimeParameterRequest *pRequest) + { + write(RingBufferCommand::ParameterRequest,pRequest); + } + void ParameterRequestComplete(RealtimeParameterRequest *pRequest) + { + write(RingBufferCommand::ParameterRequestComplete,pRequest); + } + void MidiValueChanged(int64_t instanceId, int controlIndex,float value) + { + MidiValueChangedBody body; + body.instanceId = instanceId; + body.controlIndex = controlIndex; + body.value = value; + write(RingBufferCommand::MidiValueChanged,body); + } + + void OnMidiListen(bool isNote, uint8_t noteOrControl) { + uint16_t msg = noteOrControl; + if (isNote) msg |= 0x100; + write(RingBufferCommand::OnMidiListen, msg); + } + + void SetControlValue(int effectIndex, int controlIndex, float value) + { + SetControlValueBody body; + body.effectIndex = effectIndex; + body.controlIndex = controlIndex; + body.value = value; + write(RingBufferCommand::SetValue,body); + } + + void FreeVuSubscriptions(RealtimeVuBuffers *configuration) + { + write(RingBufferCommand::FreeVuSubscriptions, configuration); + } + void FreeMonitorPortSubscriptions(RealtimeMonitorPortSubscriptions *subscriptions) + { + + write(RingBufferCommand::FreeMonitorPortSubscription, subscriptions); + } + + void SendMonitorPortUpdate( + PortMonitorCallback* callback, + int64_t subscriptionHandle, + float value) + { + MonitorPortUpdate body{callback, subscriptionHandle, value}; + write(RingBufferCommand::SendMonitorPortUpdate, body); + } + + void SendVuUpdate(const std::vector *pUpdates) + { + write(RingBufferCommand::SendVuUpdate,pUpdates); + } + void AckVuUpdate() + { + bool value = true; + write(RingBufferCommand::AckVuUpdate,value); + } + void AckMonitorPortUpdate(int64_t subscriptionHandle) + { + // we assume no padding between the command and the data, so we can do an atomic write. + + write(RingBufferCommand::AckMonitorPortUpdate, subscriptionHandle); + } + void SetVuSubscriptions(RealtimeVuBuffers *configuration) + { + write(RingBufferCommand::SetVuSubscriptions, configuration); + } + + void SetMonitorPortSubscriptions(RealtimeMonitorPortSubscriptions *subscriptions) + { + + write(RingBufferCommand::SetMonitorPortSubscription, subscriptions); + } + + void SetBypass(int effectIndex, bool enabled) + { + + SetBypassBody body; + body.effectIndex = effectIndex; + body.enabled = enabled; + write(RingBufferCommand::SetBypass,body); + } + + void ReplaceEffect(Lv2PedalBoard *pedalBoard) + { + write(RingBufferCommand::ReplaceEffect, pedalBoard); + } + + void AudioStopped() + { + AudioStoppedBody body; + write(RingBufferCommand::AudioStopped, body); + } + + void EffectReplaced(Lv2PedalBoard *pedalBoard) + { + write(RingBufferCommand::EffectReplaced, pedalBoard); + } + }; + +} //namespace \ No newline at end of file diff --git a/src/Scratch.cpp b/src/Scratch.cpp new file mode 100644 index 0000000..21483be --- /dev/null +++ b/src/Scratch.cpp @@ -0,0 +1,32 @@ +#include "pch.h" + + +class TargetClass +{ +public: + void read(int*t) { } + void read(double*t) { } + void read2(double*t) { } +}; + +#ifdef JUNK + +template +class HasJsonRead { + + + template + static std::true_type test (decltype(TargetClass().read((ARG*)nullptr))*v) { return std::true_type();}; + + template + static std::false_type test (...); + +public: + static constexpr bool value = decltype(test(nullptr))::value; +}; + +class X{ + static_assert(HasJsonRead::value,"TEST FAILED."); +}; + +#endif \ No newline at end of file diff --git a/src/Shutdown.hpp b/src/Shutdown.hpp new file mode 100644 index 0000000..dcb36f8 --- /dev/null +++ b/src/Shutdown.hpp @@ -0,0 +1,4 @@ +#pragma once + + +void Shutdown(); // implemented in main.cpp \ No newline at end of file diff --git a/src/ShutdownClient.cpp b/src/ShutdownClient.cpp new file mode 100644 index 0000000..6c7a671 --- /dev/null +++ b/src/ShutdownClient.cpp @@ -0,0 +1,140 @@ +#include "pch.h" +#include "ShutdownClient.hpp" +#include "PiPedalException.hpp" +#include +#include +#include +#include "Lv2Log.hpp" +#include + +using namespace pipedal; + + + +extern uint16_t g_ShutdownPort; // set in main.cpp + + +bool ShutdownClient::CanUseShutdownClient() +{ + return g_ShutdownPort != 0; +} + + + + +bool ShutdownClient::RequestShutdown(bool restart) +{ + const char*message = restart? "restart\n": "shutdown\n"; + return WriteMessage(message); +} + +bool ShutdownClient::WriteMessage(const char*message) { + + uint16_t shutdownServerPort = g_ShutdownPort; + if (g_ShutdownPort == 0) + { + throw PiPedalException("No shutdown server available."); + } + + struct sockaddr_in serv_addr; + + memset(&serv_addr,0,sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(shutdownServerPort); + if (inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr) <= 0) + { + Lv2Log::error("Failed to parse socket address."); + return false; + } + int sock = socket(AF_INET,SOCK_STREAM,0); + if (sock < 0) + { + Lv2Log::error("Can't create socket."); + return false; + } + + if (connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) + { + std::stringstream s; + s << "Connect to 127.0.0.1:" << shutdownServerPort << " failed."; + Lv2Log::error(s.str()); + close(sock); + return false; + } + int length = strlen(message); + const char *p = message; + + bool success = true; + while (length != 0) { + auto nWritten = write(sock,p,length); + if (nWritten < 0) + { + success = false; + Lv2Log::error("Shutdown server write failed."); + close(sock); + return false; + } + p += nWritten; + length -= nWritten; + } + shutdown(sock, SHUT_WR); + char responseBuffer[1024]; + ssize_t available = sizeof(responseBuffer); + char *pWrite = responseBuffer; + char*pEndOfLine = responseBuffer; + + bool eolFound = false; + while (!eolFound) + { + ssize_t nRead = read(sock,pWrite,available); + if (nRead <= 0) { + Lv2Log::error("Failed to read shutdown server response."); + close(sock); + return false; + + } + pWrite += nRead; + available -= nRead; + if (available == 0) + { + Lv2Log::error("Bad response from shutdown server."); + close(sock); + return false; + } + + while (pEndOfLine != pWrite) + { + if (*pEndOfLine++ == '\n') + { + eolFound = true; + pEndOfLine[-1] = '\0'; + break; + } + } + } + int response = atoi(responseBuffer); + close(sock); + if (response == -2) // throw exception with message + { + const char *p = responseBuffer; + while (*p != ' ' && *p != '\n' && *p != '\0') + { + ++p; + } + if (*p != 0) ++p; + throw PiPedalStateException(p); + } + return response == 0; +} + +bool ShutdownClient::SetJackServerConfiguration(const JackServerSettings & jackServerSettings) +{ + std::stringstream s; + s << "setJackConfiguration " + << jackServerSettings.GetSampleRate() + << " " << jackServerSettings.GetBufferSize() + << " " << jackServerSettings.GetNumberOfBuffers() + << "\n"; + + return WriteMessage(s.str().c_str()); +} diff --git a/src/ShutdownClient.hpp b/src/ShutdownClient.hpp new file mode 100644 index 0000000..62cf96c --- /dev/null +++ b/src/ShutdownClient.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "JackServerSettings.hpp" + +namespace pipedal { + +class ShutdownClient { + static bool WriteMessage(const char*message); +public: + static bool CanUseShutdownClient(); + static bool RequestShutdown(bool restart); + static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings); +}; + +} // namespace \ No newline at end of file diff --git a/src/ShutdownMain.cpp b/src/ShutdownMain.cpp new file mode 100644 index 0000000..326c51b --- /dev/null +++ b/src/ShutdownMain.cpp @@ -0,0 +1,350 @@ +// shim file to allow shutdown to be called from a service. +// (Gets suid root permissions during install, since otherwise +// non-interactive services are not allowed to execute) + +#include "pch.h" +#include "CommandLineParser.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include "JackServerSettings.hpp" +#include +#include "Lv2Log.hpp" +#include "Lv2SystemdLogger.hpp" + + +using namespace std; +using namespace pipedal; +using namespace boost; +using namespace boost::asio; +using ip::tcp; + +const size_t MAX_LENGTH = 128; + +static bool startsWith(const std::string&s, const char*text) +{ + if (s.length() < strlen(text)) return false; + const char*sp = s.c_str(); + while (*text) + { + if (*text++ != *sp++) return false; + } + return true; +} +static std::vector tokenize(std::string value) +{ + std::vector result; + std::stringstream s(value); + std::string item; + while (std::getline(s,item,' ')) + { + if (item.length() != 0) + result.push_back(item); + } + return result; +} + +static void CaptureAccessPoint(const std::string gatewayAddress) +{ + +} +static void ReleaseAccessPoint(const std::string gatewayAddress) +{ +} + +bool setJackConfiguration(uint32_t sampleRate,uint32_t bufferSize,uint32_t numberOfBuffers) +{ + bool success = true; + JackServerSettings serverSettings(sampleRate,bufferSize,numberOfBuffers); + + try { + serverSettings.Write(); + } catch (const std::exception &e) { + std::stringstream s; + s << "Failed to write jackdrc settings. " << e.what(); + Lv2Log::error(s.str()); + success = false; + } + ::system("pulseaudio --kill"); + + if (::system("systemctl restart jack") != 0) + { + Lv2Log::error("Failed to restart jack server."); + success = false; + } + return false; + + +} + +class Reader : public std::enable_shared_from_this +{ +private: + tcp::socket socket; + int readAvailable = MAX_LENGTH; + char data[MAX_LENGTH]; + char *writePointer; + ssize_t writeLength; + std::stringstream message; + + size_t writePosition = 0; + std::string response; + +public: + Reader(io_service &ios) + : socket(ios) + { + } + static std::shared_ptr Create(io_service &ios) + { + return std::make_shared(ios); + } + + tcp::socket &Socket() { return socket; } + + void Start() + { + ReadSome(); + } + +private: + void ReadSome() + { + socket.async_read_some( + boost::asio::buffer(data, readAvailable), + boost::bind(&Reader::HandleRead, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + void WriteSome() + { + if (writePosition == response.size()) + { + socket.close(); + return; + } + socket.async_write_some( + boost::asio::buffer(response.c_str()+ writePosition, response.length()-writePosition), + boost::bind(&Reader::HandleWrite, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + +private: + void HandleWrite(const boost::system::error_code &err, size_t bytes_transferred) + { + writePosition += bytes_transferred; + WriteSome(); + } + void HandleRead(const boost::system::error_code &err, size_t bytes_transferred) + { + if (!err) + { + for (size_t i = 0; i < bytes_transferred; ++i) + { + char c = data[i]; + if (c == '\n') + { + std::string command = message.str(); + cout << "Received command: " << command << endl; + HandleCommand(command); + socket.close(); + return; + } + else + { + message.put(data[i]); + } + } + ReadSome(); + } + else + { + socket.close(); + } + } + void HandleCommand(const std::string &s) + { + int result = -1; + try { + if (startsWith(s,"release_ap ")) + { + std::vector argv = tokenize(s); + if (argv.size() == 2) { + ReleaseAccessPoint(argv[1]); + result = 0; + } else { + throw PiPedalArgumentException("Invalid arguments."); + } + + } else if (startsWith(s,"capture_ap ")) + { + std::vector argv = tokenize(s); + if (argv.size() == 2) { + CaptureAccessPoint(argv[1]); + result = 0; + } else { + throw PiPedalArgumentException("Invalid arguments."); + } + + + } else if (s == "shutdown") + { + result = ::system("/usr/sbin/shutdown -P now"); + } + else if (s == "restart") + { + result = ::system("/usr/sbin/shutdown -r now"); + } else if (startsWith(s,"setJackConfiguration ")) + { + auto remainder = s.substr(strlen("setJackConfiguration ")); + + std::stringstream input(remainder); + uint32_t sampleRate; + uint32_t bufferSize; + uint32_t numberOfBuffers; + input >> sampleRate >> bufferSize >> numberOfBuffers; + if (input.fail()) + { + result = -1; + } else { + result = setJackConfiguration(sampleRate,bufferSize,numberOfBuffers) ? 0: -1; + } + + } + } catch (const std::exception &e) + { + std::stringstream t; + t << "-2 " << e.what(); + this->response = t.str(); + this->writePosition = 0; + WriteSome(); + return; + } + + std::stringstream t; + t << result << "\n"; + this->response = t.str(); + this->writePosition = 0; + WriteSome(); + } + +}; + +class Server +{ +private: + tcp::acceptor acceptor_; + + void HandleAccept(std::shared_ptr connection, const boost::system::error_code &err) + { + if (!err) + { + connection->Start(); + } + StartAccept(); + } + + void StartAccept() + { + // socket + std::shared_ptr reader = Reader::Create(acceptor_.get_io_service()); + + // asynchronous accept operation and wait for a new connection. + acceptor_.async_accept(reader->Socket(), + boost::bind(&Server::HandleAccept, this, reader, + boost::asio::placeholders::error)); + } + +public: + //constructor for accepting connection from client + Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint) + : acceptor_(io_service, endpoint) + { + StartAccept(); + } + ~Server() { + + } +}; + +void runServer(uint16_t port) +{ + asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port); + asio::io_service ios; + + try { + Server server(ios,endpoint); + ios.run(); + cout << "Processing terminated." << endl; + } catch (const std::exception & e) + { + cout << "Error: " << e.what() << endl; + } +} + +int main(int argc, char **argv) +{ + + Lv2Log::set_logger(MakeLv2SystemdLogger()); + CommandLineParser parser; + + uint16_t port = 0; + std::string captureAccessPoint; + std::string releaseAccessPoint; + + parser.AddOption("-port", &port); + parser.AddOption("-captureAP",&captureAccessPoint); + parser.AddOption("-releaseAP",&releaseAccessPoint); + + try + { + parser.Parse(argc, (const char **)argv); + if (parser.Arguments().size() != 0) + { + throw PiPedalException("Invalid argument."); + } + } + catch (const std::exception &e) + { + cout << "Error: " << e.what() << endl; + return EXIT_FAILURE; + } + if (captureAccessPoint.length() != 0) + { + try{ + CaptureAccessPoint(captureAccessPoint); + + } catch (const std::exception &e) + { + std::cerr << "Error: " << e.what() << std::endl; + return EXIT_FAILURE; + } + std::cout << "Access point captured." << std::endl; + } else if (releaseAccessPoint.length() != 0) + { + try{ + ReleaseAccessPoint(releaseAccessPoint); + } catch (const std::exception &e) + { + std::cerr << "Error: " << e.what() << std::endl; + return EXIT_FAILURE; + } + std::cout << "Access point released." << std::endl; + + } else { + if (port == 0) { + std::cerr << "Error: port not specified." << std::endl; + return EXIT_FAILURE; + } + runServer(port); + } + return EXIT_SUCCESS; +} diff --git a/src/SplitEffect.cpp b/src/SplitEffect.cpp new file mode 100644 index 0000000..4cd0af0 --- /dev/null +++ b/src/SplitEffect.cpp @@ -0,0 +1,165 @@ +#include "pch.h" +#include "SplitEffect.hpp" + +#include "Lv2Host.hpp" +#include "PedalBoard.hpp" + +using namespace pipedal; + + +static std::shared_ptr MakeBypassPortInfo() { + std::shared_ptr bypassPortInfo = std::make_shared(); + bypassPortInfo->symbol("__bypass"); + bypassPortInfo->name("Bypass"); + bypassPortInfo->is_input(true); + bypassPortInfo->is_control_port(true); + bypassPortInfo->index(-1); + bypassPortInfo->min_value(0); + bypassPortInfo->max_value(1); + bypassPortInfo->default_value(1); + bypassPortInfo->toggled_property(true); + return bypassPortInfo; +} + +std::shared_ptr g_BypassPortInfo = MakeBypassPortInfo(); + +// Pseudo-port info used to perform midi port value mapping. +const Lv2PortInfo *pipedal::GetBypassPortInfo() +{ + return g_BypassPortInfo.get(); +} +// Just enough to do control value defaulting, and midi value mapping :-/ + + + + +static Lv2PluginInfo makeSplitterPluginInfo() { + Lv2PluginInfo result; + result.uri(SPLIT_PEDALBOARD_ITEM_URI); + result.name("Split"); + result.author_name("Robin Davies"); + result.comment("Internal only."); + result.is_valid(true); + + std::shared_ptr splitTypeControl= std::make_shared(); + splitTypeControl->symbol(SPLIT_SPLITTYPE_KEY); + splitTypeControl->name("Type"); + splitTypeControl->is_input(true); + splitTypeControl->is_control_port(true); + splitTypeControl->index(0); + splitTypeControl->min_value(0); + splitTypeControl->max_value(2); + splitTypeControl->default_value(0); + splitTypeControl->enumeration_property(true); + splitTypeControl->scale_points().push_back( + Lv2ScalePoint(0,"A/B") + ); + splitTypeControl->scale_points().push_back( + Lv2ScalePoint(1,"Mix") + ); + splitTypeControl->scale_points().push_back( + Lv2ScalePoint(1,"L/R") + ); + result.ports().push_back(splitTypeControl); + + + std::shared_ptr abControl= std::make_shared(); + abControl->symbol(SPLIT_SELECT_KEY); + abControl->name("Select"); + abControl->is_input(true); + abControl->is_control_port(true); + abControl->index(1); + abControl->min_value(0); + abControl->max_value(1); + abControl->default_value(0); + abControl->enumeration_property(true); + abControl->scale_points().push_back( + Lv2ScalePoint(0,"A") + ); + abControl->scale_points().push_back( + Lv2ScalePoint(1,"B") + ); + result.ports().push_back(abControl); + + std::shared_ptr mixControl= std::make_shared(); + mixControl->symbol(SPLIT_MIX_KEY); + mixControl->name("Mix"); + mixControl->is_input(true); + mixControl->is_control_port(true); + mixControl->index(2); + mixControl->min_value(-1); + mixControl->max_value(1); + mixControl->default_value(0); + + result.ports().push_back(mixControl); + + std::shared_ptr panLControl= std::make_shared(); + panLControl->symbol(SPLIT_PANL_KEY); + panLControl->name("Pan L"); + panLControl->is_input(true); + panLControl->is_control_port(true); + panLControl->index(3); + panLControl->min_value(-1); + panLControl->max_value(1); + panLControl->default_value(0); + + result.ports().push_back(panLControl); + + std::shared_ptr volLControl= std::make_shared(); + volLControl->symbol(SPLIT_VOLL_KEY); + volLControl->name("Vol L"); + volLControl->is_input(true); + volLControl->is_control_port(true); + volLControl->index(4); + volLControl->min_value(-60); + volLControl->max_value(12); + volLControl->default_value(-3); + volLControl->scale_points().push_back( + Lv2ScalePoint(-60,"-INF") + ); + + result.ports().push_back(volLControl); + + std::shared_ptr panRControl= std::make_shared(); + panRControl->symbol(SPLIT_PANR_KEY); + panRControl->name("Pan R"); + panRControl->is_input(true); + panRControl->is_control_port(true); + panRControl->index(5); + panRControl->min_value(-1); + panRControl->max_value(1); + panRControl->default_value(0); + + result.ports().push_back(panRControl); + + std::shared_ptr volRControl= std::make_shared(); + volRControl->symbol(SPLIT_VOLR_KEY); + volRControl->name("Vol R"); + volRControl->is_input(true); + volRControl->is_control_port(true); + volRControl->index(6); + volRControl->min_value(-60); + volRControl->max_value(12); + volRControl->default_value(-3); + volRControl->scale_points().push_back( + Lv2ScalePoint(-60,"-INF") + ); + + result.ports().push_back(volRControl); + + + + + + return result; +} + + +Lv2PluginInfo g_splitterPluginInfo = makeSplitterPluginInfo(); + +const Lv2PluginInfo * pipedal::GetSplitterPluginInfo() { return &g_splitterPluginInfo; } + + + + + diff --git a/src/SplitEffect.hpp b/src/SplitEffect.hpp new file mode 100644 index 0000000..0301f55 --- /dev/null +++ b/src/SplitEffect.hpp @@ -0,0 +1,652 @@ +#pragma once + +#include "IEffect.hpp" +#include "PiPedalException.hpp" +#include "PiPedalMath.hpp" + +namespace pipedal +{ + + enum class SplitType + { + Ab = 0, + Mix = 1, + Lr = 2 + }; + class Lv2PluginInfo; + class Lv2PortInfo; + + const Lv2PluginInfo *GetSplitterPluginInfo(); + + const Lv2PortInfo *GetBypassPortInfo(); + + + const double SPLIT_DB_MIN = -60; + + inline SplitType valueToSplitType(float value) + { + switch ((int)value) + { + case 0: + return SplitType::Ab; + case 1: + return SplitType::Mix; + case 2: + return SplitType::Lr; + default: + return SplitType::Ab; + } + }; + + class SplitEffect : public IEffect + { + private: + const double MIX_TRANSITION_TIME_S = 0.1; + double sampleRate; + std::vector inputs; + std::vector topInputs; + std::vector bottomInputs; + std::vector topOutputs; + std::vector bottomOutputs; + + std::vector mixTopInputs; + std::vector mixBottomInputs; + + std::vector outputBuffers; + int numberOfOutputPorts; + + SplitType splitType = SplitType::Ab; + float mix = 0; + float panL = 0; + float volL = -3; + float panR = 0; + float volR = -3; + + float currentMix = 0; + + float targetBlendLTop = 0.5; + float targetBlendRTop = 0.5; + float targetBlendLBottom = 0.5; + float targetBlendRBottom = 0.5; + + float blendLTop = 0.5; + float blendRTop = 0.5; + float blendLBottom = 0.5; + float blendRBottom = 0.5; + + float blendDxLTop = 0; + float blendDxRTop = 0; + float blendDxLBottom = 0; + float blendDxRBottom = 0; + + int32_t blendFadeSamples; + + bool selectA = true; + + bool activated = false; + + using MixFunction = void (SplitEffect::*)(uint32_t frames); + + MixFunction preAbTop; + MixFunction preAbBottom; + + void Copy(float *input, float *output, uint32_t frames) + { + for (int i = 0; i < frames; ++i) + { + output[i] = input[i]; + } + } + + void AbTopMonoMono(uint32_t frames) + { + Copy(this->inputs[0], this->topInputs[0], frames); + } + void AbTopMonoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->topInputs[0], frames); + Copy(this->inputs[0], this->topInputs[1], frames); + } + void AbTopStereoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->topInputs[0], frames); + Copy(this->inputs[1], this->topInputs[1], frames); + } + + void AbBottomMonoMono(uint32_t frames) + { + Copy(this->inputs[0], this->bottomInputs[0], frames); + } + void AbBottomMonoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->bottomInputs[0], frames); + Copy(this->inputs[0], this->bottomInputs[1], frames); + } + void AbBottomStereoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->bottomInputs[0], frames); + Copy(this->inputs[1], this->bottomInputs[1], frames); + } + void LrTopMonoMono(uint32_t frames) + { + Copy(this->inputs[0], this->topInputs[0], frames); + } + void LrTopMonoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->topInputs[0], frames); + Copy(this->inputs[0], this->topInputs[1], frames); + } + void LrTopStereoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->topInputs[0], frames); + Copy(this->inputs[0], this->topInputs[1], frames); + } + + void LrBottomMonoMono(uint32_t frames) + { + Copy(this->inputs[0], this->bottomInputs[0], frames); + } + void LrBottomMonoStereo(uint32_t frames) + { + Copy(this->inputs[0], this->bottomInputs[0], frames); + Copy(this->inputs[0], this->bottomInputs[1], frames); + } + void LrBottomStereoStereo(uint32_t frames) + { + Copy(this->inputs[1], this->bottomInputs[0], frames); + Copy(this->inputs[1], this->bottomInputs[1], frames); + } + + void UpdateMixFunction() + { + if (activated) + { + + // Input Mix Functions. + if (splitType != SplitType::Lr) + { + if (this->inputs.size() == 1) + { + if (this->topInputs.size() == 1) + this->preAbTop = &SplitEffect::AbTopMonoMono; + else + { + this->preAbTop = &SplitEffect::AbTopMonoStereo; + } + if (this->bottomInputs.size() == 1) + { + this->preAbBottom = &SplitEffect::AbBottomMonoMono; + } + else + { + this->preAbBottom = &SplitEffect::AbBottomMonoStereo; + } + } + else + { + if (this->topInputs.size() == 1) + { + this->preAbTop == &SplitEffect::AbTopMonoMono; + } + else + { + this->preAbTop = &SplitEffect::AbTopStereoStereo; + } + if (this->bottomInputs.size() == 1) + { + this->preAbBottom == &SplitEffect::AbBottomMonoMono; + } + else + { + this->preAbBottom = &SplitEffect::AbBottomStereoStereo; + } + } + } + else + { + if (this->inputs.size() == 1) + { + if (this->topInputs.size() == 1) + this->preAbTop = &SplitEffect::LrTopMonoMono; + else + { + this->preAbTop = &SplitEffect::LrTopMonoStereo; + } + if (this->bottomInputs.size() == 1) + { + this->preAbBottom = &SplitEffect::LrBottomMonoMono; + } + else + { + this->preAbBottom = &SplitEffect::LrBottomMonoStereo; + } + } + else + { + if (this->topInputs.size() == 1) + { + this->preAbTop == &SplitEffect::LrTopMonoMono; + } + else + { + this->preAbTop = &SplitEffect::LrTopStereoStereo; + } + if (this->bottomInputs.size() == 1) + { + this->preAbBottom == &SplitEffect::LrBottomMonoMono; + } + else + { + this->preAbBottom = &SplitEffect::LrBottomStereoStereo; + } + } + } + if (splitType == SplitType::Ab) + { + mixTo(selectA ? -1 : 1); + } + else if (splitType == SplitType::Mix) + { + mixTo(mix); + } + else + { + mixTo(panL, volL, panR, volR); + } + } + } + long instanceId; + + virtual uint8_t *GetAtomInputBuffer() { return nullptr; } + virtual uint8_t *GetAtomOutputBuffer() { return nullptr; } + virtual void RequestParameter(LV2_URID uridUri) {} + virtual void GatherParameter(RealtimeParameterRequest *pRequest) {} + virtual std::string AtomToJson(uint8_t *pAtom) { return ""; } + + public: + SplitEffect( + long instanceId, + double sampleRate, + const std::vector &inputs) + : instanceId(instanceId), inputs(inputs), sampleRate(sampleRate) + + { + } + ~SplitEffect() + { + } + + + virtual long GetInstanceId() const + { + return instanceId; + } + void Activate() + { + activated = true; + UpdateMixFunction(); + snapToMixTarget(); + + mixBottomInputs.clear(); + mixTopInputs.clear(); + + if (outputBuffers.size() == 1) + { + mixTopInputs.push_back(this->topOutputs[0]); + mixBottomInputs.push_back(this->bottomOutputs[0]); + } + else + { + if (this->topOutputs.size() == 1) + { + mixTopInputs.push_back(topOutputs[0]); + mixTopInputs.push_back(topOutputs[0]); + } + else + { + mixTopInputs.push_back(topOutputs[0]); + mixTopInputs.push_back(topOutputs[1]); + } + if (this->bottomOutputs.size() == 1) + { + mixBottomInputs.push_back(bottomOutputs[0]); + mixBottomInputs.push_back(bottomOutputs[0]); + } + else + { + mixBottomInputs.push_back(bottomOutputs[0]); + mixBottomInputs.push_back(bottomOutputs[1]); + } + } + } + void Deactivate() + { + activated = false; + } + + void SetChainBuffers( + const std::vector &topInputs, + const std::vector &bottomInputs, + const std::vector &topOutputs, + const std::vector &bottomOutputs) + { + this->topInputs = topInputs; + this->bottomInputs = bottomInputs; + this->topOutputs = topOutputs; + this->bottomOutputs = bottomOutputs; + + numberOfOutputPorts = topOutputs.size() > 1 || bottomOutputs.size() > 1 ? 2 : 1; + outputBuffers.resize(numberOfOutputPorts); + } + virtual void ResetAtomBuffers() {} + virtual int GetControlIndex(const std::string &symbol) const + { + if (symbol == "splitType") + return 0; + if (symbol == "select") + return 1; + if (symbol == "mix") + return 2; + return -1; + } + + void snapToMixTarget() + { + this->blendLTop = targetBlendLTop; + this->blendRTop = targetBlendRTop; + this->blendRBottom = targetBlendRBottom; + this->blendLBottom = targetBlendLBottom; + this->blendFadeSamples = 0; + this->blendDxLTop = 0; + this->blendDxRTop = 0; + this->blendDxLBottom = 0; + this->blendDxRBottom = 0; + } + void mixToTarget() + { + uint32_t transitionSamples = (uint32_t)(this->sampleRate * MIX_TRANSITION_TIME_S); + if (transitionSamples < 1) + transitionSamples = 1; + double dxScale = 1.0 / transitionSamples; + this->blendFadeSamples = transitionSamples; + this->blendDxLTop = dxScale * (this->targetBlendLTop - this->blendLTop); + this->blendDxRTop = dxScale * (this->targetBlendRTop - this->blendRTop); + this->blendDxLBottom = dxScale * (this->targetBlendLBottom - this->blendLBottom); + this->blendDxRBottom = dxScale * (this->targetBlendRBottom - this->blendRBottom); + } + + void mixTo(float value) + { + float blend = (value + 1) * 0.5f; + this->targetBlendRTop = this->targetBlendLTop = 1 - blend; + this->targetBlendLBottom = this->targetBlendLBottom = blend; + mixToTarget(); + } + void mixTo(float panL, float volL, float panR, float volR) + { + float aTop = (volL <= SPLIT_DB_MIN) ? 0 : db2a(volL); + float aBottom = (volL <= SPLIT_DB_MIN) ? 0 : db2a(volR); + if (this->outputBuffers.size() == 1) + { + // ignore pan. The R values actually have no effect. + this->targetBlendLTop = this->targetBlendRTop = aTop; + this->targetBlendLBottom = this->targetBlendRBottom = aBottom; + } + else + { + float blendTop = (panL + 1) * 0.5; + float blendBottom = (panR + 1) * 0.5; + this->targetBlendLTop = (1 - blendTop) * aTop; + this->targetBlendRTop = (blendTop)*aTop; + this->targetBlendLBottom = (1 - blendBottom) * aBottom; + this->targetBlendRBottom = (blendBottom)*aBottom; + } + mixToTarget(); + } + virtual void SetBypass(bool enabled) + { + throw PiPedalArgumentException("Not implmented. Should not have been called."); + } + + virtual float GetOutputControlValue(int index) const { + return GetControlValue(index); + } + + virtual float GetControlValue(int portIndex) const + { + switch (portIndex) + { + case -1: /* (bypass) */ + return 1; + case 0: + { + return (int)(this->splitType); + } + case 1: + { + return selectA ? 0 : 1; + } + case 2: + return mix; + case 3: + return this->panL; + case 4: + return this->volL; + case 5: + return this->panR; + case 6: + return this->volR; + default: + throw PiPedalArgumentException("Invalid argument"); + } + } + virtual void SetControl(int index, float value) + { + switch (index) + { + case -1: /* (bypass) */ + return; // no can bypass. + case 0: + { + SplitType t = valueToSplitType(value); + if (splitType != t) + { + splitType = t; + UpdateMixFunction(); + } + break; + } + case 1: + { + bool t = value == 0; + if (selectA != t) + { + selectA = t; + + if (splitType == SplitType::Ab) + { + mixTo(selectA ? -1 : 1); + } + } + break; + } + case 2: + mix = value; + if (splitType == SplitType::Mix) + { + mixTo(value); + } + break; + case 3: + panL = value; + if (splitType == SplitType::Lr) + { + mixTo(panL, volL, panR, volR); + } + break; + case 4: + volL = value; + if (splitType == SplitType::Lr) + { + mixTo(panL, volL, panR, volR); + } + break; + case 5: + panR = value; + if (splitType == SplitType::Lr) + { + mixTo(panL, volL, panR, volR); + } + break; + case 6: + volR = value; + if (splitType == SplitType::Lr) + { + mixTo(panL, volL, panR, volR); + } + break; + } + } + + virtual int GetNumberOfOutputAudioPorts() const + { + return numberOfOutputPorts; + } + virtual int GetNumberOfInputAudioPorts() const + { + return (int)this->inputs.size(); + } + virtual float *GetAudioInputBuffer(int index) const + { + return inputs[index]; + } + virtual float *GetAudioOutputBuffer(int index) const + { + return this->outputBuffers[index]; + } + + virtual void SetAudioOutputBuffer(int index, float *buffer) + { + outputBuffers[index] = buffer; + } + void PreMix(uint32_t frames) + { + (this->*preAbTop)(frames); + (this->*preAbBottom)(frames); + } + + void PostMixMono(uint32_t frames) + { + uint32_t ix = 0; + + float *top = this->mixTopInputs[0]; + float *bottom = this->mixBottomInputs[0]; + float *output = this->outputBuffers[0]; + + while (frames) + { + if (this->blendFadeSamples != 0) + { + uint32_t framesThisTime = this->blendFadeSamples < frames ? this->blendFadeSamples : frames; + for (uint32_t i = 0; i < framesThisTime; ++i) + { + output[ix] = blendLBottom * bottom[ix] + blendLTop * top[ix]; + ++ix; + + this->blendLTop += this->blendDxLTop; + this->blendLBottom += this->blendDxLBottom; + } + this->blendFadeSamples -= framesThisTime; + frames -= framesThisTime; + if (blendFadeSamples == 0) + { + this->blendLTop = this->targetBlendLTop; + this->blendLBottom = this->targetBlendLBottom; + this->blendDxLTop = this->blendDxLBottom = 0; + } + } + else + { + float blendTop = this->blendLTop; + float blendBottom = this->blendLBottom; + while (frames--) + { + output[ix] = blendBottom * bottom[ix] + blendTop * top[ix]; + ++ix; + } + return; + } + } + } + + void PostMixStereo(uint32_t frames) + { + uint32_t ix = 0; + + float *top = this->mixTopInputs[0]; + float *bottom = this->mixBottomInputs[0]; + float *output = this->outputBuffers[0]; + + float *topR = this->mixTopInputs[1]; + float *bottomR = this->mixBottomInputs[1]; + float *outputR = this->outputBuffers[1]; + + while (frames != 0) + { + if (this->blendFadeSamples != 0) + { + uint32_t framesThisTime = this->blendFadeSamples < frames ? this->blendFadeSamples : frames; + for (int i = 0; i < framesThisTime; ++i) + { + output[ix] = blendLBottom * bottom[ix] + blendLTop * top[ix]; + outputR[ix] = blendRBottom * bottomR[ix] + blendRTop * topR[ix]; + ++ix; + + this->blendLTop += this->blendDxLTop; + this->blendRTop += this->blendDxRTop; + this->blendLBottom += this->blendDxLBottom; + this->blendRBottom += this->blendDxRBottom; + } + blendFadeSamples -= framesThisTime; + frames -= framesThisTime; + if (blendFadeSamples == 0) + { + this->blendLTop = this->targetBlendLTop; + this->blendRTop = this->targetBlendRTop; + this->blendLBottom = this->targetBlendLBottom; + this->blendRBottom = this->targetBlendRBottom; + this->blendDxLTop = this->blendDxRTop = this->blendDxLBottom = this->blendDxRBottom = 0; + } + } + else + { + float blendLTop = this->blendLTop; + float blendRTop = this->blendRTop; + float blendLBottom = this->blendLBottom; + float blendRBottom = this->blendRBottom; + + for (int i = 0; i < frames; ++i) + { + output[ix] = blendLBottom * bottom[ix] + blendLTop * top[ix]; + outputR[ix] = blendRBottom * bottomR[ix] + blendRTop * topR[ix]; + ++ix; + } + return; + } + } + } + + void PostMix(uint32_t frames) + { + if (this->outputBuffers.size() == 1) + { + PostMixMono(frames); + } + else + { + PostMixStereo(frames); + } + } + }; + +} // namespace \ No newline at end of file diff --git a/src/Storage.cpp b/src/Storage.cpp new file mode 100644 index 0000000..1d860f7 --- /dev/null +++ b/src/Storage.cpp @@ -0,0 +1,685 @@ +#include "pch.h" +#include "Storage.hpp" +#include "PiPedalException.hpp" +#include +#include "json.hpp" +#include +#include "Lv2Log.hpp" + +using namespace pipedal; + +const char *BANK_EXTENSION = ".bank"; +const char *BANKS_FILENAME = "index.banks"; + +Storage::Storage() +{ + SetDataRoot("~/var/PiPedal"); +} + +inline bool isSafeCharacter(char c) +{ + return (c >= '0' && c <= '9') | (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '-'; +} + +static int fromhexStrict(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + // lowercase letters won't round-trip properly. + return -1; +} + +std::string Storage::SafeDecodeName(const std::string &name) +{ + std::stringstream s; + for (int i = 0; i < name.length(); /**/) + { + char c = name[i++]; + if (c < ' ') + throw PiPedalArgumentException("Unsafe file name."); + + if (c == '+') + { + s << ' '; + } + else if (c == '%') + { + if (i + 2 > name.length()) + { + throw PiPedalArgumentException("Unsafe file name."); + } + int v1 = fromhexStrict(name[i]); + int v2 = fromhexStrict(name[i + 1]); + i += 2; + if (v1 == -1 || v2 == -1) + throw PiPedalArgumentException("Unsafe file name."); + char c = (char)((v1 << 4) + v2); + if (isSafeCharacter(c)) + { + // name won't round-trip because the escape will not be re-encoded. + throw PiPedalArgumentException("Unsafe file name."); + } + s << c; + } + else + { + if (isSafeCharacter(c)) + { + s << c; + } + else + { + throw PiPedalArgumentException("Unsafe file name."); + } + } + } + return s.str(); +} + +static const char *hex = "0123456789ABCDEF"; + +std::string Storage::SafeEncodeName(const std::string &name) +{ + std::stringstream s; + for (char c : name) + { + if (c < ' ') + c = ' '; + bool safe = isSafeCharacter(c); + if (safe) + { + s << c; + } + else if (c == ' ') + { + s << '+'; + } + else + { + s << '%' << hex[(c >> 4) & 0x0F] << hex[(c)&0x0F]; + } + } + return s.str(); +} + +std::filesystem::path ResolveHomePath(std::filesystem::path path) +{ + if (path.begin() == path.end()) + return path; + // is the first element "~"? + auto it = path.begin(); + auto el = (*it); + if (el != "~") + return path; + const char *homeDirectory = nullptr; + + homeDirectory = getenv("HOME"); + if (homeDirectory == nullptr) + { + homeDirectory = getenv("USERPROFILE"); + } + std::filesystem::path result = homeDirectory; + + bool first = true; + for (auto i = path.begin(); i != path.end(); ++i) + { + if (!first) + { + result /= *i; + } + first = false; + } + return result; +} +void Storage::SetDataRoot(const char *path) +{ + this->dataRoot = ResolveHomePath(path); +} + +void Storage::Initialize() +{ + try + { + std::filesystem::create_directories(this->GetPresetsDirectory()); + } + catch (const std::exception &e) + { + throw PiPedalStateException("Can't create presets directory. (" + (std::string)this->GetPresetsDirectory() + ") (" + e.what() + ")"); + } + LoadBankIndex(); + LoadCurrentBank(); + try + { + LoadChannelSelection(); + } + catch (const std::exception &) + { + } +} + +void Storage::LoadBank(int64_t instanceId) +{ + auto indexEntry = this->bankIndex.getBankIndexEntry(instanceId); + + LoadBankFile(indexEntry.name(), &(this->currentBank)); + if (this->bankIndex.selectedBank() != instanceId) + { + this->bankIndex.selectedBank(instanceId); + SaveBankIndex(); + } + this->LoadPreset(this->bankIndex.selectedBank()); +} + +void Storage::LoadCurrentBank() +{ + LoadBank(bankIndex.selectedBank()); +} + +std::filesystem::path Storage::GetPresetsDirectory() const +{ + return this->dataRoot / "presets"; +} + +std::filesystem::path Storage::GetChannelSelectionFileName() +{ + return this->dataRoot / "JackChannelSelection.json"; +} +std::filesystem::path Storage::GetIndexFileName() +{ + return this->GetPresetsDirectory() / BANKS_FILENAME; +} +std::filesystem::path Storage::GetBankFileName(const std::string &name) +{ + std::string fileName = SafeEncodeName(name) + BANK_EXTENSION; + return this->GetPresetsDirectory() / fileName; +} + +void Storage::LoadBankIndex() +{ + try + { + auto path = GetIndexFileName(); + std::ifstream s; + s.open(path); + json_reader reader(s); + reader.read(&bankIndex); + } + catch (const std::exception &) + { + bankIndex.clear(); + ReIndex(); + + if (bankIndex.entries().size() == 0) + { + currentBank.clear(); + PedalBoard defaultPedalBoard = PedalBoard::MakeDefault(); + int64_t instanceId = currentBank.addPreset(defaultPedalBoard); + currentBank.selectedPreset(instanceId); + + std::string name = "Default Bank"; + SaveBankFile(name, currentBank); + int64_t selectedBank = bankIndex.addBank(-1,name); + bankIndex.selectedBank(selectedBank); + } + SaveBankIndex(); + } +} +void Storage::SaveBankIndex() +{ + std::ofstream os; + os.open(GetIndexFileName(), std::ios_base::trunc); + json_writer writer(os); + writer.write(this->bankIndex); +} + +void Storage::ReIndex() +{ + for (const auto &dirEntry : std::filesystem::directory_iterator(GetPresetsDirectory())) + { + if (!dirEntry.is_directory()) + { + auto path = dirEntry.path(); + if (path.extension() == BANK_EXTENSION) + { + std::string name = SafeDecodeName(path.stem()); + bankIndex.addBank(-1,name); + } + } + } + if (bankIndex.entries().size() == 0) + { + CreateBank("Default Bank"); + } + bankIndex.selectedBank(bankIndex.entries()[0].instanceId()); +} + +void Storage::CreateBank(const std::string &name) +{ + BankFile bankFile; + PedalBoard defaultPreset = PedalBoard::MakeDefault(); + defaultPreset.name(std::string("Default Preset")); + + bankFile.addPreset(defaultPreset); + + int64_t instanceId = bankFile.presets()[0]->instanceId(); + bankFile.selectedPreset(instanceId); + SaveBankFile(name, bankFile); + this->bankIndex.addBank(-1,name); + this->SaveBankIndex(); +} + +void Storage::LoadBankFile(const std::string &name, BankFile *pBank) +{ + std::filesystem::path fileName = GetBankFileName(name); + std::ifstream is(fileName); + json_reader reader(is); + reader.read(pBank); + +} + +void Storage::SaveBankFile(const std::string &name, const BankFile &bankFile) +{ + std::filesystem::path fileName = GetBankFileName(name); + std::filesystem::path backupFile = ((std::string)fileName) + ".$$$"; + if (std::filesystem::exists(backupFile)) + { + std::filesystem::remove(backupFile); + } + if (std::filesystem::exists(fileName)) + { + std::filesystem::rename(fileName, backupFile); + } + try + { + std::ofstream s; + s.open(fileName, std::ios_base::trunc); + json_writer writer(s); + writer.write(bankFile); + if (std::filesystem::exists(backupFile)) + { + std::filesystem::remove(backupFile); + } + } + catch (const std::exception &e) + { + std::filesystem::remove(fileName); + if (std::filesystem::exists(backupFile)) + { + std::filesystem::rename(backupFile, fileName); + } + throw; + } +} + +void Storage::SaveCurrentBank() +{ + auto indexEntry = this->bankIndex.getBankIndexEntry(this->bankIndex.selectedBank()); + SaveBankFile(indexEntry.name(), this->currentBank); +} + +const PedalBoard &Storage::GetCurrentPreset() +{ + auto &item = currentBank.getItem(currentBank.selectedPreset()); + return item.preset(); +} + +bool Storage::LoadPreset(int64_t instanceId) +{ + if (!currentBank.hasItem(instanceId)) + return false; + currentBank.selectedPreset(instanceId); + SaveCurrentBank(); + return true; +} +void Storage::saveCurrentPreset(const PedalBoard &pedalBoard) +{ + auto &item = currentBank.getItem(currentBank.selectedPreset()); + item.preset(pedalBoard); + SaveCurrentBank(); +} +int64_t Storage::saveCurrentPresetAs(const PedalBoard &pedalBoard, const std::string &name, int64_t saveAfterInstanceId) +{ + PedalBoard newPedalBoard = pedalBoard; + newPedalBoard.name(name); + + int64_t newInstanceId = currentBank.addPreset(newPedalBoard, saveAfterInstanceId); + currentBank.selectedPreset(newInstanceId); + SaveCurrentBank(); + return newInstanceId; +} + +void Storage::SetPresetIndex(const PresetIndex &presets) +{ + // painful because we must move unique_ptrs. + std::map *> entries; + for (int i = 0; i < this->currentBank.presets().size(); ++i) + { + auto & preset = this->currentBank.presets()[i]; + entries[preset->instanceId()] = &(this->currentBank.presets()[i]); + } + std::vector*> newPresets; + for (size_t i = 0; i < presets.presets().size(); ++i) + { + std::unique_ptr* p = entries[presets.presets()[i].instanceId()]; + if (p == nullptr) + { + throw PiPedalStateException("Presets do not match the currently loaded bank."); + } + newPresets.push_back(p); + } + // we made it this far. So now we know we can rebuild a new BankFile. + BankFile bankFile; + bankFile.presets().resize(newPresets.size()); + for (int i = 0; i < presets.presets().size(); ++i) + { + std::unique_ptr *oldBankFilePreset = newPresets[i]; + + bankFile.presets()[i] = std::move((*oldBankFilePreset)); + } + bankFile.nextInstanceId(currentBank.nextInstanceId()); + bankFile.selectedPreset(currentBank.selectedPreset()); + + this->currentBank = std::move(bankFile); // deleting any stray presets while we're at it. + this->SaveCurrentBank(); +} +void Storage::GetPresetIndex(PresetIndex *pResult) +{ + *pResult = PresetIndex(); + pResult->selectedInstanceId(this->currentBank.selectedPreset()); + for (auto &item : this->currentBank.presets()) + { + PresetIndexEntry entry; + entry.instanceId(item->instanceId()); + entry.name(item->preset().name()); + pResult->presets().push_back(entry); + } +} +PedalBoard Storage::GetPreset(int64_t instanceId) const +{ + for (size_t i = 0; i < currentBank.presets().size(); ++i) + { + if (currentBank.presets()[i]->instanceId() == instanceId) + { + return currentBank.presets()[i]->preset(); + } + } + throw PiPedalException("Not found."); +} + +int64_t Storage::DeletePreset(int64_t presetId) +{ + int64_t newSelection = currentBank.deletePreset(presetId); + SaveCurrentBank(); + return newSelection; +} + +bool Storage::RenamePreset(int64_t presetId, const std::string &name) +{ + if (this->currentBank.renamePreset(presetId, name)) + { + SaveCurrentBank(); + return true; + } + return false; +} + +static int lastIndexOf(const char *sz, char c) +{ + size_t len = strlen(sz); + for (size_t i = len - 1; i >= 0; --i) + { + if (sz[i] == c) + { + if (i > 0 && sz[i - 1] == ' ') + --i; + return i; + } + } + return -1; +} +std::string Storage::GetPresetCopyName(const std::string &name) +{ + const char *str = name.c_str(); + std::string stem; + if (name.length() != 0 && name[name.length() - 1] == ')') + { + const char *str = name.c_str(); + size_t pos = lastIndexOf(str, '('); + if (pos == -1) + { + stem = name; + } + else + { + stem = name.substr(0, pos); + } + } + else + { + stem = name; + } + int copyNumber = 1; + while (true) + { + std::string candidate; + if (copyNumber == 1) + { + candidate = stem + " (Copy)"; + } + else + { + std::stringstream s; + s << stem << " (Copy " << copyNumber << ")"; + candidate = s.str(); + } + if (!this->currentBank.hasName(candidate)) + { + return candidate; + } + ++copyNumber; + } +} +int64_t Storage::CopyPreset(int64_t fromId, int64_t toId) +{ + auto &fromItem = this->currentBank.getItem(fromId); + if (toId == -1) + { + PedalBoard newPedalBoard = fromItem.preset(); + std::string name = GetPresetCopyName(fromItem.preset().name()); + newPedalBoard.name(name); + return this->currentBank.addPreset(newPedalBoard, fromId); + } + else + { + auto &toItem = this->currentBank.getItem(toId); + toItem.preset(fromItem.preset()); + return toId; + } +} + +void Storage::SetJackChannelSelection(const JackChannelSelection &channelSelection) +{ + this->jackChannelSelection = channelSelection; + this->isJackChannelSelectionValid = true; + SaveChannelSelection(); +} +const JackChannelSelection &Storage::GetJackChannelSelection(const JackConfiguration &jackConfiguration) +{ + if (!this->isJackChannelSelectionValid) + { + if (jackConfiguration.isValid()) + { + auto defaultSelection = JackChannelSelection::MakeDefault(jackConfiguration); + SetJackChannelSelection(defaultSelection); + return this->jackChannelSelection; + } + } + return jackChannelSelection; +} + +void Storage::LoadChannelSelection() +{ + auto fileName = this->GetChannelSelectionFileName(); + if (std::filesystem::exists(fileName)) + { + try + { + std::ifstream s(fileName); + json_reader reader(s); + reader.read(&this->jackChannelSelection); + this->isJackChannelSelectionValid = true; + } + catch (const std::exception &e) + { + Lv2Log::error("I/O error reading %s: %s", fileName.c_str(), e.what()); + throw PiPedalStateException("Unexpected error reading Jack settings file."); + } + } +} +void Storage::SaveChannelSelection() +{ + auto fileName = this->GetChannelSelectionFileName(); + try + { + std::ofstream s(fileName); + json_writer writer(s); + writer.write(this->jackChannelSelection); + } + catch (const std::exception &e) + { + Lv2Log::error("I/O error writing %s: %s", fileName.c_str(), e.what()); + throw PiPedalStateException("Unexpected error writing Jack settings file."); + } +} + +void Storage::RenameBank(int64_t bankId, const std::string &newName) +{ + auto existingBank = this->bankIndex.getEntryByName(newName); + if (existingBank != nullptr) + { + throw PiPedalStateException("A bank by that name already exists."); + } + auto &entry = this->bankIndex.getBankIndexEntry(bankId); + std::filesystem::path oldPath = this->GetBankFileName(entry.name()); + std::filesystem::path newPath = this->GetBankFileName(newName); + try + { + std::filesystem::rename(oldPath, newPath); + } + catch (std::exception &e) + { + std::stringstream s; + s << "Unable to rename the bank. (" << e.what() << ")"; + throw PiPedalException(s.str()); + } + entry.name(newName); + SaveBankIndex(); +} + +int64_t Storage::SaveBankAs(int64_t bankId, const std::string &newName) +{ + auto existingBank = this->bankIndex.getEntryByName(newName); + if (existingBank != nullptr) + { + throw PiPedalStateException("A bank by that name already exists."); + } + auto &entry = this->bankIndex.getBankIndexEntry(bankId); + std::filesystem::path oldPath = this->GetBankFileName(entry.name()); + std::filesystem::path newPath = this->GetBankFileName(newName); + try + { + std::filesystem::copy(oldPath,newPath); + } + catch (std::exception &e) + { + std::stringstream s; + s << "Unable to save the bank. (" << e.what() << ")"; + throw PiPedalException(s.str()); + } + int64_t newId = this->bankIndex.addBank(bankId,newName); + SaveBankIndex(); + return newId; +} + +void Storage::MoveBank(int from, int to) +{ + this->bankIndex.move(from,to); + this->SaveBankIndex(); +} +int64_t Storage::DeleteBank(int64_t bankId) +{ + auto & entries = this->bankIndex.entries(); + + for (size_t i = 0; i < entries.size(); ++i) + { + auto & entry = entries[i]; + + if (entry.instanceId() == bankId) { + std::filesystem::path fileName = this->GetBankFileName(entry.name()); + entries.erase(entries.begin()+i); + + int64_t newSelection; + if (i < entries.size()) + { + newSelection = entries[i].instanceId(); + } else if (entries.size() > 0) + { + newSelection = entries[entries.size()-1].instanceId(); + } else { + // zero entries? + // Create a default empty bank. + BankIndexEntry newEntry; + + BankFile defaultBank; + PedalBoard defaultPedalBoard = PedalBoard::MakeDefault(); + int64_t instanceId = defaultBank.addPreset(defaultPedalBoard); + defaultBank.selectedPreset(instanceId); + + std::string name = "Default Bank"; + SaveBankFile(name, defaultBank); + int64_t selectedBank = bankIndex.addBank(-1,name); + newSelection = selectedBank; + } + if (this->bankIndex.selectedBank() == bankId) + { + this->bankIndex.selectedBank(newSelection); + } + this->SaveBankIndex(); + std::filesystem::remove(fileName); + return newSelection; + } + } + throw PiPedalStateException("Bank not found."); +} + +int64_t Storage::UploadPreset(const BankFile&bankFile,int64_t uploadAfter) +{ + int64_t lastPreset = this->currentBank.selectedPreset(); + if (uploadAfter != -1) + { + lastPreset = uploadAfter; + } + + if (bankFile.presets().size() == 0) { + throw PiPedalException("Invalid preset."); + } + for (size_t i = 0; i < bankFile.presets().size(); ++i) + { + PedalBoard preset = bankFile.presets()[i]->preset(); + + int n = 2; + std::string baseName = preset.name(); + while (this->currentBank.hasName(preset.name())) + { + std::stringstream s; + s << baseName << "(" << n++ << ")"; + preset.name(s.str()); + } + + lastPreset = this->currentBank.addPreset(preset,lastPreset); + } + this->SaveCurrentBank(); + return lastPreset; +} diff --git a/src/Storage.hpp b/src/Storage.hpp new file mode 100644 index 0000000..1a874d6 --- /dev/null +++ b/src/Storage.hpp @@ -0,0 +1,84 @@ +#pragma once +#include +#include +#include "PedalBoard.hpp" +#include "Presets.hpp" +#include "Banks.hpp" +#include "JackConfiguration.hpp" + + +namespace pipedal { + + +// controls user-defined storage. Implmentation hidden to allow to later migration to a database (perhaps) + +class Storage { +private: + std::filesystem::path dataRoot; + BankIndex bankIndex; + BankFile currentBank; + +private: + static std::string SafeEncodeName(const std::string& name); + static std::string SafeDecodeName(const std::string& name); + std::filesystem::path GetPresetsDirectory() const; + std::filesystem::path GetIndexFileName(); + std::filesystem::path GetBankFileName(const std::string & name); + std::filesystem::path GetChannelSelectionFileName(); + + void LoadBankIndex(); + void SaveBankIndex(); + void ReIndex(); + void LoadCurrentBank(); + void SaveCurrentBank(); + + void LoadChannelSelection(); + void SaveChannelSelection(); + void SaveBankFile(const std::string& name,const BankFile&bankFile); + void LoadBankFile(const std::string &name,BankFile *pBank); + std::string GetPresetCopyName(const std::string &name); + bool isJackChannelSelectionValid = false; + JackChannelSelection jackChannelSelection; +public: + Storage(); + void Initialize(); + void CreateBank(const std::string & name); + + void SetDataRoot(const char*path); + + std::vector GetPedalBoards(); + + const BankIndex & GetBanks() const { return bankIndex; } + + + void LoadBank(int64_t instanceId); + const PedalBoard& GetCurrentPreset(); + void saveCurrentPreset(const PedalBoard&pedalBoard); + int64_t saveCurrentPresetAs(const PedalBoard&pedalBoard, const std::string&namne,int64_t saveAfterInstanceId = -1); + + void GetPresetIndex(PresetIndex*pResult); + void SetPresetIndex(const PresetIndex &presetIndex); + PedalBoard GetPreset(int64_t instanceId) const; + int64_t UploadPreset(const BankFile&bankFile, int64_t uploadAfter); + + + bool LoadPreset(int64_t presetId); + int64_t DeletePreset(int64_t presetId); + bool RenamePreset(int64_t presetId, const std::string&name); + int64_t CopyPreset(int64_t fromId, int64_t toId = -1); + + void RenameBank(int64_t bankId, const std::string&newName); + int64_t SaveBankAs(int64_t bankId, const std::string&newName); + + void MoveBank(int from, int to); + int64_t DeleteBank(int64_t bankId); + + + void SetJackChannelSelection(const JackChannelSelection&channelSelection); + const JackChannelSelection&GetJackChannelSelection(const JackConfiguration &jackConfiguration); + + +}; + + +} // namespace pipedal \ No newline at end of file diff --git a/src/Units.cpp b/src/Units.cpp new file mode 100644 index 0000000..5ec5de2 --- /dev/null +++ b/src/Units.cpp @@ -0,0 +1,135 @@ +#include "pch.h" +#include "Units.hpp" +#include "PiPedalException.hpp" +#include + +#include "lv2/lv2plug.in/ns/extensions/units/units.h" + + +using namespace pipedal; + +Units UriToUnits(const std::string &uri); + + +#define CASE(name) \ + { Units::name, #name }, + + +std::map unitsToStringMap = +{ + CASE(none) + CASE(unknown) + + CASE(bar) + CASE(beat) + CASE(bpm) + CASE(cent) + CASE(cm) + CASE(db) + CASE(hz) + CASE(khz) + CASE(km) + CASE(m) + CASE(mhz) + CASE(midiNote) + CASE(min) + CASE(ms) + CASE(pc) + CASE(s) + CASE(semitone12TET) + +}; + +const std::string& pipedal::UnitsToString(Units units) +{ + return unitsToStringMap[units]; +} +#undef CASE + +#define CASE(name) \ + { #name, Units::name}, + +std::map unitMap = { + CASE(none) + CASE(unknown) + CASE(bar) + CASE(beat) + CASE(bpm) + CASE(cent) + CASE(cm) + CASE(db) + CASE(hz) + CASE(khz) + CASE(km) + CASE(m) + CASE(mhz) + CASE(midiNote) + CASE(min) + CASE(ms) + CASE(pc) + CASE(s) + CASE(semitone12TET) +}; +#undef CASE + +#define CASE(name) \ + { LV2_UNITS__##name, Units::name}, + + + +std::map uriToUnitsMap = { + CASE(bar) + CASE(beat) + CASE(bpm) + CASE(cent) + CASE(cm) + CASE(db) + CASE(hz) + CASE(khz) + CASE(km) + CASE(m) + CASE(mhz) + CASE(midiNote) + CASE(min) + CASE(ms) + CASE(pc) + CASE(s) + CASE(semitone12TET) +}; + + +Units pipedal::StringToUnits(const std::string &text) +{ + return unitMap[text]; +} + +Units pipedal::UriToUnits(const std::string &text) +{ + if (text.length() == 0) return Units::none; + auto result = uriToUnitsMap[text]; + if (result == Units::none) return Units::unknown; + return result; + +} + + + +class UnitsEnumConverter: public json_enum_converter { +public: + virtual Units fromString(const std::string&value) const + { + return StringToUnits(value); + } + virtual const std::string& toString(Units value) const + { + return UnitsToString(value); + } + + +} g_units_converter; + + +json_enum_converter *pipedal::get_units_enum_converter() +{ + return &g_units_converter; +} diff --git a/src/Units.hpp b/src/Units.hpp new file mode 100644 index 0000000..638ff0d --- /dev/null +++ b/src/Units.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include "json.hpp" + +namespace pipedal { + +enum class Units { + none, + unknown, + bar, + beat, + bpm, + cent, + cm, + db, + hz, + khz, + km, + m, + mhz, + midiNote, + min, + ms, + pc, + s, + semitone12TET, + +}; + +Units UriToUnits(const std::string &uri); +const std::string& UnitsToString(Units units); +Units StringToUnits(const std::string &text); + + + + +json_enum_converter *get_units_enum_converter(); + + + +} // namespace. + diff --git a/src/Uri.cpp b/src/Uri.cpp new file mode 100644 index 0000000..89db6f9 --- /dev/null +++ b/src/Uri.cpp @@ -0,0 +1,449 @@ +#include "pch.h" +#include "Uri.hpp" +#include "HtmlHelper.hpp" +#include "PiPedalException.hpp" + +using namespace pipedal; + +std::string uri::segment(int index) const +{ + const char *p = path_start; + int segment = 0; + + if (p != path_end && *p == '/') ++p; + + while (p != path_end && *p != '?' && *p != '#') + { + if (segment == index) + { + const char*segmentStart = p; + while(p != path_end && *p != '/' && *p != '?' && *p != '#') + { + ++p; + } + return HtmlHelper::decode_url_segment(segmentStart,p); + } else { + while(p != path_end && *p != '/' && *p != '?' && *p != '#') + { + ++p; + } + } + if (p != path_end && *p == '/') ++p; + ++segment; + } + throw std::invalid_argument("Invalid segement number."); +}; + + +int uri::segment_count() const { + const char *p = path_start; + int segment = 0; + + if (p != path_end && *p == '/') ++p; + + while (p != path_end && *p != '?' && *p != '#') + { + while(p != path_end && *p != '/' && *p != '?' && *p != '#') + { + ++p; + } + if (p != path_end && *p == '/') ++p; + ++segment; + } + return segment; +} + +void uri::set(const char*start, const char*end) +{ + this->text = std::string(start,end); + set_(); +} +void uri::set(const char*text) +{ + this->text = text; + set_(); +} + +void uri::set_() +{ + const char*start = this->text.c_str(); + const char*end = start+this->text.size(); + + const char* p = start; + + this->isRelative = true; + + bool hasScheme = false; + while (p != end) + { + char c = *p; + if (c == ':') { + hasScheme = true; + break; + } + if (c == '/' || c == '?' || c == '#') + { + break; + } + ++p; + } + if (hasScheme) + { + scheme_start = start; + scheme_end = p; + ++p; + } else { + scheme_start = start; + scheme_end = start; + p = start; + } + if (p[0] == '/' && p[1] == '/') + { + this->isRelative = false; + // authority. + p += 2; + + user_start = p; + user_end = p; + authority_start = p; + authority_end = nullptr; + + const char*port_start = nullptr; + while (p != end) + { + char c = *p; + if (c == '@') + { + user_end = p; + authority_start = p+1; + port_start = nullptr; + } else if (c == ':') + { + authority_end = p; + port_start = p+1; + } + if (c == '/' || c == '?' || c == '#') + { + break; + } + ++p; + } + if (authority_end == nullptr) authority_end = p; + if (port_start != nullptr) + { + char*intEnd; + port_ = (int)std::strtol(port_start,&intEnd,10); + if (intEnd != p) throwInvalid(); + } else { + port_ = -1; + } + } else { + user_start = p; + user_end = p; + authority_start = p; + authority_end = p; + port_ = -1; + } + + path_start = p; + if (p != end && *p == '/') this->isRelative = false; + + while (p != end && *p != '?' && *p != '#') + { + ++p; + } + path_end = p; + + if (p != end && *p == '?') + { + ++p; + query_start = p; + while (p != end && *p != '#') + { + ++p; + } + query_end = p; + } else { + query_start = query_end = p; + } + if (p != end && *p == '#') + { + ++p; + fragment_start = p; + fragment_end = end; + + } else { + fragment_start = fragment_end = p; + } +} + +void uri::throwInvalid() { + throw std::invalid_argument("Invalid uri."); + +} + +static bool compare_name(const char*start, const char*end, const char*szName) +{ + while (start != end) + { + if (*start != *szName) return false; + ++start; ++szName; + } + return *szName == 0; +} + +int uri::query_count() const +{ + int count = 0; + const char*p = query_start; + while (p != query_end && *p != '#') + { + const char*nameStart = p; + while (p != query_end && *p != '&' && *p != '#') + { + ++p; + } + if (p != query_end && *p == '&') ++p; + ++count; + if (p == query_end || *p == '#') + { + break; + + } + } + return count; + +} + +bool uri::has_query(const char*name) const +{ + const char*p = query_start; + while (p != query_end && *p != '#') + { + const char*nameStart = p; + while (p != query_end && *p != '&' && *p != '=' && *p != '#') + { + ++p; + } + // compare names. + if (compare_name(nameStart,p,name)) + { + return true; + } + while (p != query_end && *p != '&' && *p != '#') + { + ++p; + } + if (p != query_end && *p == '&') ++p; + } + return false; + +} + +query_segment uri::query(int index) const +{ + const char*p = query_start; + int ix = 0; + while (p != query_end && *p != '#') + { + const char*nameStart = p; + while (p != query_end && *p != '&' && *p != '=' && *p != '#') + { + ++p; + } + // compare names. + + //if (compare_name(nameStart,p,name)) + if (ix == index) + { + const char *nameEnd = p; + if (p != query_end && *p == '=') + { + ++p; + const char*value_start = p; + while(p != query_end && *p != '&' && *p != '#') + { + ++p; + } + return query_segment( + std::string(nameStart,nameEnd), + std::string(value_start,p) + ); + + } else { + return query_segment( + std::string(nameStart,nameEnd), + "" + ); + } + } + while (p != query_end && *p != '&' && *p != '#') + { + ++p; + } + if (p != query_end && *p == '&') + { + ++p; + } + ++ix; + + } + throw PiPedalArgumentException("Index out of range."); +} + +std::string uri::query(const char*name) const +{ + const char*p = query_start; + while (p != query_end && *p != '#') + { + const char*nameStart = p; + while (p != query_end && *p != '&' && *p != '=' && *p != '#') + { + ++p; + } + // compare names. + if (compare_name(nameStart,p,name)) + { + if (p != query_end && *p == '=') + { + ++p; + const char*value_start = p; + while(p != query_end && *p != '&' && *p != '#') + { + ++p; + } + return HtmlHelper::decode_url_segment(value_start,p); + } else { + return ""; + } + } + while (p != query_end && *p != '&' && *p != '#') + { + ++p; + } + if (p != query_end && *p == '&') + { + ++p; + } + + } + return ""; +} + +query_segment uri::query(int index) +{ + const char*p = query_start; + int count = 0; + while (p != query_end && *p != '#') + { + if (count == index) + { + const char*nameStart = p; + while (p != query_end && *p != '&' && *p != '=' && *p != '#') + { + ++p; + } + const char *nameEnd = p; + const char *valueStart, *valueEnd; + + if(p == query_end || *p != '=') + { + valueStart = valueEnd = p; + } else { + ++p; + valueStart = p; + + while(p != query_end && *p != '&' && *p != '#') + { + ++p; + } + valueEnd = p; + } + return query_segment(std::string(nameStart,nameEnd), HtmlHelper::decode_url_segment(valueStart,valueEnd)); + } else { + while (p != query_end && *p != '&' && *p != '#') + { + ++p; + } + + } + if (p != query_end && *p == '&') ++p; + ++count; + } + throw std::invalid_argument("Argument out of range."); +} + +std::vector uri::segments() +{ + std::vector result; + for (int i = 0; i < segment_count(); ++i) + { + result.push_back(segment(i)); + } + return result; +} + +std::string uri::get_extension() const +{ + const char*p = this->path_end; + while (p != this->path_start) + { + char c = p[-1]; + if (c == '/') return ""; + if (c == '.') { + --p; + return std::string(p,this->path_end-p); + } + --p; + } + return ""; +} + +std::string uri::to_canonical_form() const { + uri_builder builder(*this); + return builder.str(); +} + +std::string uri_builder::str() const { + std::stringstream s; + if (scheme_.length() != 0) + { + s << scheme_ << ':'; + } + if (authority_.length() != 0) { + s << "//"; + if (user_.length() != 0) + { + s << user_ << '@'; + } + s << authority_; + if (port_ != -1) { + s << ':' << (uint16_t)port_; + } + } + if ( authority_.length() != 0 || !isRelative_) { // canonical root form is http://xyz/ not httP://xyz + + s << '/'; + } + for (size_t i = 0; i < segments_.size(); ++i) + { + if (i != 0) s << '/'; + HtmlHelper::encode_url_segment(s,segments_[i],false); + } + if (queries_.size() != 0) + { + s << '?'; + for (size_t i = 0; i < queries_.size(); ++i) + { + s << queries_[i].key << "="; + HtmlHelper::encode_url_segment(s,queries_[i].value,true); + } + + } + if (fragment_.length() != 0) + { + s << "#" << fragment_; + } + return s.str(); + +} \ No newline at end of file diff --git a/src/Uri.hpp b/src/Uri.hpp new file mode 100644 index 0000000..7cee53c --- /dev/null +++ b/src/Uri.hpp @@ -0,0 +1,214 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace pipedal { + + +class query_segment { + +public: + query_segment(const std::string &key, const std::string &value) + : key(key) + , value(value) { + + } + const std::string key; + const std::string value; + + bool operator==(const query_segment &other) + { + return key == other.key && value == other.value; + } +}; + + +class uri +{ +private: + std::string text; + const char*scheme_start, *scheme_end; + const char *user_start, *user_end; + const char* authority_start, *authority_end; + const char* path_start, *path_end; + bool isRelative; + int port_; + const char*query_start, *query_end; + const char*fragment_start, *fragment_end; +public: + uri() + { + set(""); + } + const std::string& str() { + return text; + } + uri(const char*text) + { + set(text); + } + void set(const char*text); + void set(const char*start, const char*end); +private: + void set_(); + static void throwInvalid(); +public: + bool has_scheme() const { return scheme_start != scheme_end; } + std::string scheme() const{ return std::string(scheme_start, scheme_end); } + + bool has_user() const{ return user_start != user_end; } + std::string user() const{ return std::string(user_start,user_end); } + + bool has_authority() const{ return authority_start != authority_end; } + std::string authority() const{ return std::string(authority_start,authority_end);} + + bool has_port() const{ return port_ != -1; } + int port() const{ return port_; } + + bool is_relative() const { return isRelative; } + + std::string path() const { return std::string(path_start, path_end); } + + int segment_count() const; + + std::string segment(int n) const; + + std::vector segments(); + const std::vector segments() const; + + int query_count() const; + + query_segment query(int index); + + bool has_query(const char*name) const; + + std::string query(const char*name) const; + query_segment query(int index) const; + + std::string get_extension() const; + + std::string fragment() const { return std::string(fragment_start, fragment_end);} + + std::string to_canonical_form() const; + +}; + +class uri_builder { + +private: + std::string scheme_ = "http"; + std::string user_ = ""; + std::string authority_ = ""; + int port_ = -1; + bool isRelative_ = false; + std::vector segments_; + + std::vector queries_; + std::string fragment_; + +public: + uri_builder() + { + + } + + uri_builder(const uri&uri) + : scheme_(uri.scheme()), + user_(uri.user()), + authority_(uri.authority()), + port_(uri.port()), + isRelative_(uri.is_relative()), + fragment_(uri.fragment()) + { + for (int i = 0; i < uri.segment_count(); ++i) + { + segments_.push_back(uri.segment(i)); + } + for (int i = 0; i < uri.query_count(); ++i) + { + queries_.push_back(uri.query(i)); + } + } + std::string str() const; + + const std::string & scheme() const { return scheme_; } + void set_scheme(const std::string &scheme_) { + this->scheme_ = scheme_; + } + const std::string & user() const { return this->user_;} + void set_user(const std::string&user) { this->user_ = user; } + + const std::string &authority() const { + return this->authority_; + } + void set_authority(const std::string &authority) { + this->authority_ = authority; + } + int port() const { return port_; } + void set_port(int port) { + this->port_ = port; + } + + bool is_relative() const { return this->isRelative_ && authority_.length() == 0; } + void set_is_relative(bool isRelative) + { + this->isRelative_ = isRelative; + } + int segment_count() const { return (int)segments_.size(); } + const std::string& segment(int i) const { return segments_[i];} + + void append_segment(const std::string & segment) { + segments_.push_back(segment); + } + void insert_segment(int position, std::string & segment) { + segments_.insert(segments_.begin()+position,segment); + } + void erase_segment(int position) + { + segments_.erase(segments_.begin()+position); + } + void replace_segment(int position, std::string& segment) { + segments_[position] = segment; + } + + + int query_count() const { return (int)(queries_.size());} + + bool has_query(const std::string &key) const { + for (size_t i = 0; i < queries_.size(); ++i) + { + if (queries_[i].key == key) true; + } + return false; + + } + std::string query(const std::string &key) const { + for (size_t i = 0; i < queries_.size(); ++i) + { + if (queries_[i].key == key) return queries_[i].value; + } + return ""; + } + std::vector queries(const std::string &key) const { + std::vector result; + for (size_t i = 0; i < queries_.size(); ++i) + { + if (queries_[i].key == key) result.push_back(queries_[i].value); + } + return result; + } + const query_segment & query(int index) { + return queries_[index]; + } + + const std::string&fragment() { return this->fragment_; } + void set_fragment(const std::string & fragment) { this->fragment_ = fragment;} + + +}; +}; // namespace pipedal. + diff --git a/src/VuUpdate.cpp b/src/VuUpdate.cpp new file mode 100644 index 0000000..235e39f --- /dev/null +++ b/src/VuUpdate.cpp @@ -0,0 +1,17 @@ +#include "pch.h" +#include "VuUpdate.hpp" + +using namespace pipedal; + + +JSON_MAP_BEGIN(VuUpdate) + JSON_MAP_REFERENCE(VuUpdate,instanceId) + JSON_MAP_REFERENCE(VuUpdate,sampleTime) + JSON_MAP_REFERENCE(VuUpdate,isStereoInput) + JSON_MAP_REFERENCE(VuUpdate,isStereoOutput) + JSON_MAP_REFERENCE(VuUpdate,inputMaxValueL) + JSON_MAP_REFERENCE(VuUpdate,inputMaxValueR) + JSON_MAP_REFERENCE(VuUpdate,outputMaxValueL) + JSON_MAP_REFERENCE(VuUpdate,outputMaxValueR) +JSON_MAP_END() + diff --git a/src/VuUpdate.hpp b/src/VuUpdate.hpp new file mode 100644 index 0000000..3c607d1 --- /dev/null +++ b/src/VuUpdate.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "json.hpp" + +namespace pipedal +{ + class VuUpdate + { + public: + long instanceId_ = 0; + long sampleTime_ = 0; + bool isStereoInput_ = false; + bool isStereoOutput_ = false; + float inputMaxValueL_ = 0; + float inputMaxValueR_ = 0; + float outputMaxValueL_ = 0; + float outputMaxValueR_ = 0; + + public: + void reset() { + inputMaxValueL_ = 0; + inputMaxValueR_ = 0; + outputMaxValueL_ = 0; + outputMaxValueR_ = 0; + } + + void AccumulateVu(float *value,float *input, uint32_t samples) + { + + float v = *value; + for (uint32_t i = 0; i < samples; ++i) + { + float t = std::abs(input[i]); + if (t > v) { + v = t; + } + } + *value = v; + } + void AccumulateInputs(float* input, uint32_t samples) + { + AccumulateVu(&inputMaxValueL_,input,samples); + + } + void AccumulateInputs(float* inputL, float*inputR, uint32_t samples) + { + AccumulateVu(&inputMaxValueL_,inputL,samples); + AccumulateVu(&inputMaxValueR_,inputR,samples); + + } + void AccumulateOutputs(float* output, uint32_t samples) + { + AccumulateVu(&outputMaxValueL_,output,samples); + + } + void AccumulateOutputs(float* outputL, float*outputR, uint32_t samples) + { + AccumulateVu(&outputMaxValueL_,outputL,samples); + AccumulateVu(&outputMaxValueR_,outputR,samples); + + } + + DECLARE_JSON_MAP(VuUpdate); + }; +} \ No newline at end of file diff --git a/src/Worker.cpp b/src/Worker.cpp new file mode 100644 index 0000000..8b1dda4 --- /dev/null +++ b/src/Worker.cpp @@ -0,0 +1,157 @@ +/* + Borrows heavily from worker.c by David Robillard. + + Copyright 2007-2012 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "Worker.hpp" +#include +#include +#include "Lv2Log.hpp" + +using namespace pipedal; + +const int RING_BUFFER_SIZE = 16 * 1024; + +Worker::Worker(LilvInstance *lilvInstance_, const LV2_Worker_Interface *workerInterface_) + : lilvInstance(lilvInstance_), + requestRingBuffer(RING_BUFFER_SIZE), + responseRingBuffer(RING_BUFFER_SIZE), + workerInterface(workerInterface_) +{ + + responseBuffer = (char *)malloc(RING_BUFFER_SIZE); + + StartWorkerThread(); +} + +Worker::~Worker() +{ + StopWorkerThread(); + sem_destroy(&requestSemaphore); + free(responseBuffer); +} + +LV2_Worker_Status Worker::worker_respond_fn(LV2_Worker_Respond_Handle handle, uint32_t size, const void *data) +{ + Worker *this_ = (Worker *)handle; + return this_->WorkerResponse(size, data); +} + +LV2_Worker_Status Worker::WorkerResponse(uint32_t size, const void *data) +{ + if (responseRingBuffer.write(sizeof(size), (uint8_t *)&size)) + { + return LV2_WORKER_ERR_NO_SPACE; + } + if (!responseRingBuffer.write(size, (uint8_t *)data)) + { + return LV2_WORKER_ERR_NO_SPACE; + } + return LV2_WORKER_SUCCESS; +} + +void Worker::EmitResponses() +{ + while (true) + { + uint32_t available = responseRingBuffer.readSpace(); + uint32_t size = 0; + if (available <= sizeof(size)) // i.e. we need a size AND a response. + break; + + responseRingBuffer.read(sizeof(size), (uint8_t *)&size); + responseRingBuffer.read(size, (uint8_t *)responseBuffer); + + workerInterface->work_response(lilvInstance->lv2_handle, size, responseBuffer); + } +} +void Worker::ThreadProc() +{ + try + { + while (true) + { + if (!requestRingBuffer.readWait()) + { + return; + } + size_t size; + while (requestRingBuffer.readSpace() > sizeof(size)) + { + if (!requestRingBuffer.read(sizeof(size), (uint8_t *)&size)) + { + throw PiPedalStateException("Working ringbuffer read failed."); + } + void *data = malloc(size); + if (!requestRingBuffer.read(size, (uint8_t *)data)) + { + throw PiPedalStateException("Working ringbuffer read failed."); + } + workerInterface->work(lilvInstance->lv2_handle, worker_respond_fn, (LV2_Handle)this, size, data); + free(data); + } + } + } + catch (const std::exception &e) + { + Lv2Log::error("Lv2 Worker thread proc exited abnormally. (%s)", e.what()); + } +} + +void Worker::StopWorkerThread() +{ + if (pThread) + { + auto pThread = this->pThread; + this->pThread = nullptr; + exiting = true; + requestRingBuffer.close(); + pThread->join(); + delete pThread; + } +} +void Worker::StartWorkerThread() +{ + auto fn = [this]() + { this->ThreadProc(); }; + this->pThread = new std::thread(fn); +} + +LV2_Worker_Status Worker::ScheduleWork( + uint32_t size, + const void *data) +{ + if (!exiting) + { + size_t space = requestRingBuffer.writeSpace(); + if (space < sizeof(size) + size) + { + return LV2_WORKER_ERR_NO_SPACE; + } + if (!requestRingBuffer.write(sizeof(size), (uint8_t *)&size)) + { + Lv2Log::debug("Not enough space in Worker ring buffer. Request failed."); + return LV2_WORKER_ERR_NO_SPACE; + } + if (!requestRingBuffer.write(size, (uint8_t *)data)) + { + // probably not going to survive. :-( + Lv2Log::error("Not enough space in Worker ring buffer. Request ring buffer probably lost sync."); + return LV2_WORKER_ERR_NO_SPACE; + } + } + return LV2_WORKER_ERR_NO_SPACE; +} diff --git a/src/Worker.hpp b/src/Worker.hpp new file mode 100644 index 0000000..8f3390d --- /dev/null +++ b/src/Worker.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include "lv2/core/lv2.h" + +#include "lv2/atom/atom.h" +#include "lv2/atom/util.h" +#include "lv2/core/lv2.h" +#include "lv2/log/log.h" +#include "lv2/log/logger.h" +#include "lv2/midi/midi.h" +#include "lv2/urid/urid.h" +#include "lv2/atom/atom.h" +#include "lv2/worker/worker.h" + +#include +#include +#include +#include +#include "RingBuffer.hpp" + + +namespace pipedal { + class Worker { + + private: + LilvInstance*lilvInstance; + const LV2_Worker_Interface*workerInterface; + + sem_t requestSemaphore; + bool exiting = false; + RingBuffer requestRingBuffer; + RingBuffer responseRingBuffer; + + char *responseBuffer; + + std::thread* pThread = nullptr; + + void ThreadProc(); + void StartWorkerThread(); + void StopWorkerThread(); + + static LV2_Worker_Status worker_respond_fn(LV2_Worker_Respond_Handle handle, uint32_t size, const void* data); + + + LV2_Worker_Status WorkerResponse(uint32_t size,const void*data); + + public: + Worker(LilvInstance *instance, const LV2_Worker_Interface *iface); + ~Worker(); + + LV2_Worker_Status ScheduleWork( + uint32_t size, + const void *data); + + void EmitResponses(); + + + }; +} \ No newline at end of file diff --git a/src/WriteTemplateFile.cpp b/src/WriteTemplateFile.cpp new file mode 100644 index 0000000..05fd434 --- /dev/null +++ b/src/WriteTemplateFile.cpp @@ -0,0 +1,47 @@ +#include "pch.h" +#include "WriteTemplateFile.hpp" +#include +#include "PiPedalException.hpp" + +using namespace pipedal; + + +void pipedal::WriteTemplateFile( + const std::map &map, + std::filesystem::path inputFile, + std::filesystem::path outputFile) +{ + std::ofstream out(outputFile); + std::ifstream in(inputFile); + + while (in.peek() != -1) + { + char c = in.get(); + if (c == '$') + { + if (in.peek() == '{') { + in.get(); + + std::stringstream sName; + try { + while ((c = in.get()) != '}') + { + sName.put(c); + } + } catch (const std::exception&) + { + throw PiPedalException("Unexpected end of file. Expecting '}'."); + } + std::string s = map.at(sName.str()); + out << s; + } else if (in.peek() == '$') + { + out.put(in.get()); + } else { + out.put(c); + } + } else { + out.put(c); + } + } +} diff --git a/src/WriteTemplateFile.hpp b/src/WriteTemplateFile.hpp new file mode 100644 index 0000000..7262418 --- /dev/null +++ b/src/WriteTemplateFile.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + + +namespace pipedal { + void WriteTemplateFile( + const std::map &map, + std::filesystem::path inputFile, + std::filesystem::path outputFile); +} \ No newline at end of file diff --git a/src/asan_options.cpp b/src/asan_options.cpp new file mode 100644 index 0000000..41e1e77 --- /dev/null +++ b/src/asan_options.cpp @@ -0,0 +1,13 @@ +#include "pch.h" + +// Options for GCC Address Sanitizer. +extern "C" { + const char* __asan_default_options() { return + "detect_leaks=0" // undesirable behavior on abnormal termination. + ":alloc_dealloc_mismatch=0" // Guitarix components trigger this. It's not actually a problem on GCC. + ":new_delete_type_mismatch=0" //GxTuner + ":print_stacktrace=1" + ":halt_on_error=1" + ; + } +} diff --git a/src/config.hpp.in b/src/config.hpp.in new file mode 100644 index 0000000..5b5713d --- /dev/null +++ b/src/config.hpp.in @@ -0,0 +1,11 @@ +#ifndef CONFIG_HPP_H +#define CONFIG_HPP_H + +#define PROJECT_NAME "@PROJECT_NAME@" +#define PROJECT_VER "@PROJECT_VERSION@" +#define PROJECT_VER_MAJOR "@PROJECT_VERSION_MAJOR@" +#define PROJECT_VER_MINOR "@PROJECT_VERSION_MINOR@" +#define PTOJECT_VER_PATCH "@PROJECT_VERSION_PATCH@" + +#endif // CONFIG_HPP_H + diff --git a/src/defer.hpp b/src/defer.hpp new file mode 100644 index 0000000..cf3be49 --- /dev/null +++ b/src/defer.hpp @@ -0,0 +1,114 @@ +#pragma once + +// ============================================================================= +// deferred_call: +// -------------- +// This struct enables us to implement deferred function calls simply in +// the defer() function below. It forces a given function to automatically +// be called at the end of scope using move-only semantics. Most +// commonly, the given function will be a lambda but that is not required. +// See the defer() function (below) for more on this +// ============================================================================= +template +struct deferred_call +{ + // Disallow assignment and copy + + + deferred_call(const deferred_call& that) = delete; + deferred_call& operator=(const deferred_call& that) = delete; + + // Pass in a lambda + + deferred_call(FUNC&& f) + : m_func(std::forward(f)), m_bOwner(true) + { + } + + // Move constructor, since we disallow the copy + + deferred_call(deferred_call&& that) + : m_func(std::move(that.m_func)), m_bOwner(that.m_bOwner) + { + that.m_bOwner = false; + } + + // Destructor forces deferred call to be executed + + ~deferred_call() + { + execute(); + } + + // Prevent the deferred call from ever being invoked + + bool cancel() + { + bool bWasOwner = m_bOwner; + m_bOwner = false; + return bWasOwner; + } + + // Cause the deferred call to be invoked NOW + + bool execute() + { + const auto bWasOwner = m_bOwner; + + if (m_bOwner) + { + m_bOwner = false; + m_func(); + } + + return bWasOwner; + } + +private: + FUNC m_func; + bool m_bOwner; +}; + + +// ----------------------------------------------------------------------------- +// defer: Generic, deferred function calls +// ---------------------------------------- +// This function template the user the ability to easily set up any +// arbitrary function to be called *automatically* at the end of +// the current scope, even if return is called or an exception is +// thrown. This is sort of a fire-and-forget. Saves you from having +// to repeat the same code over and over or from having to add +// exception blocks just to be sure that the given function is called. +// +// If you wish, you may cancel the deferred call as well as force it +// to be executed BEFORE the end of scope. +// +// Example: +// void Foo() +// { +// auto callOnException = defer([]{ SomeGlobalFunction(); }); +// auto callNoMatterWhat = defer([pObj](pObj->SomeMemberFunction(); }); +// +// // Do dangerous stuff that might throw an exception ... +// +// ... +// ... blah blah blah +// ... +// +// // Done with dangerous code. We can now... +// // a) cancel either of the above calls (i.e. call cancel()) OR +// // b) force them to be executed (i.e. call execute()) OR +// // c) do nothing and they'll be executed at end of scope. +// +// callOnException.cancel(); // no exception, prevent this from happening +// +// // End of scope, If we had not canceled or executed the two +// // above objects, they'd both be executed now. +// } +// ----------------------------------------------------------------------------- + +template +deferred_call defer(F&& f) +{ + return deferred_call(std::forward(f)); +} \ No newline at end of file diff --git a/src/functiontraits.hpp b/src/functiontraits.hpp new file mode 100644 index 0000000..84d6f19 --- /dev/null +++ b/src/functiontraits.hpp @@ -0,0 +1,26 @@ +#pragma once + + +template +struct FunctionTraitsBase +{ + using RetType = R; + using ArgTypes = std::tuple; + static constexpr std::size_t ArgCount = sizeof...(Args); +}; + +template struct FunctionTraits; + +template +struct FunctionTraits + : FunctionTraitsBase +{ + using Pointer = R(*)(Args...); +}; + +template +struct FunctionTraits + : FunctionTraitsBase +{ + using Pointer = R(*)(); +}; \ No newline at end of file diff --git a/src/json.cpp b/src/json.cpp new file mode 100644 index 0000000..0519742 --- /dev/null +++ b/src/json.cpp @@ -0,0 +1,580 @@ +#include "pch.h" +#include "json.hpp" +#include +#include +#include "PiPedalException.hpp" + +using namespace pipedal; + + + +uint32_t json_writer::continuation_byte(std::string_view::iterator &p, std::string_view::const_iterator end) +{ + if (p == end) + throw_encoding_error(); + uint8_t c = *p++; + if ((c & UTF8_CONTINUATION_MASK) != UTF8_CONTINUATION_BITS) + throw_encoding_error(); + return c & 0x3F; +} +static char hex(int v) +{ + if (v < 10) + return (char)('0' + v); + return (char)('A' + v - 10); +} + +void json_writer::throw_encoding_error() +{ + throw std::invalid_argument("Invalid UTF-8 character sequence"); +} +void json_writer::write_utf16_char(uint16_t uc) +{ + os << "\\u" + << hex((int)((uc >> 12) & 0x0F)) + << hex((int)((uc >> 8) & 0x0F)) + << hex((int)((uc >> 4) & 0x0F)) + << hex((int)((uc)&0x0F)); +} + +void json_writer::write(string_view v,bool enforceValidUtf8Encoding) +{ + // convert to utf-32. + // convert utf-32 to normalized utf-16. + // write non-7-bit and unsafe characters as \uxxxx. + + auto p = v.begin(); + os << '"'; + while (p != v.end()) + { + uint32_t uc; + uint8_t c = (uint8_t)*p++; + if ((c & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_BITS) + { + uc = c; + } + else + { + uint32_t c2 = continuation_byte(p, v.end()); + + if ((c & UTF8_TWO_BYTES_MASK) == UTF8_TWO_BYTES_BITS) + { + uint32_t c1 = c & (uint32_t)(~UTF8_TWO_BYTES_MASK); + if (c1 <= 1 && enforceValidUtf8Encoding) + { + // overlong encoding. + throw_encoding_error(); + } + uc = (c1 << 6) | c2; + } + else + { + uint32_t c3 = continuation_byte(p, v.end()); + + if ((c & UTF8_THREE_BYTES_MASK) == UTF8_THREE_BYTES_BITS) + { + uint32_t c1 = c & (uint32_t)~UTF8_THREE_BYTES_MASK; + if (c1 == 0 && c2 < 0x20 && enforceValidUtf8Encoding) + { + // overlong encoding. + throw_encoding_error(); + } + + uc = (c1) << 12 | (c2 << 6) | c3; + } + else + { + uint32_t c4 = continuation_byte(p, v.end()); + if ((c & UTF8_FOUR_BYTES_MASK) == UTF8_FOUR_BYTES_BITS) + { + uint32_t c1 = c & (uint32_t)~UTF8_FOUR_BYTES_MASK; + if (c1 == 0 && c2 < 0x10 && enforceValidUtf8Encoding) + { + // overlong encoding. + throw_encoding_error(); + } + uc = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; + } else { + // outside legal UCS range. + throw_encoding_error(); + } + } + } + } + if ((uc >= UTF16_SURROGATE_1_BASE && uc <= UTF16_SURROGATE_1_BASE + UTF16_SURROGATE_MASK) || (uc >= UTF16_SURROGATE_2_BASE && uc <= UTF16_SURROGATE_2_BASE + UTF16_SURROGATE_MASK)) + { + // MUST not encode UTF16 surrogates in UTF8. + throw_encoding_error(); + } + + if (uc == '"' || uc == '\\') + { + os << (char)'\\'; + os << (char)uc; + } + else if (uc >= 0x20 && uc < 0x80) + { + os << (char)uc; + } + else if (uc == '\r') + { + os << "\\r"; + } + else if (uc == '\n') + { + os << "\\n"; + } + else if (uc == '\t') + { + os << "\\t"; + } + else if (uc < 0x10000ul) + { + write_utf16_char((uint16_t)uc); + } + else + { + // write UTF-16 surrogate pair. + uc -= 0x10000; + + uint16_t s1 = (uint16_t)(UTF16_SURROGATE_1_BASE + ((uc >> 10) & 0x3FFu)); + uint16_t s2 = (uint16_t)(UTF16_SURROGATE_2_BASE + (uc & 0x03FFu)); + // surrogate pair. + write_utf16_char(s1); + write_utf16_char(s2); + } + } + os << '"'; +} + +void json_writer::indent() +{ + if (!compressed) + { + for (int i = 0; i < indent_level; ++i) + { + os << " "; + } + } +} + +void json_writer::start_object() +{ + os << "{" << CRLF; + indent_level += TAB_SIZE; +} +void json_writer::end_object() +{ + indent_level -= TAB_SIZE; + os << CRLF; + indent(); + os << "}"; +} + +void json_writer::start_array() +{ + indent(); + os << "[" << CRLF; + indent_level += TAB_SIZE; +} +void json_writer::end_array() +{ + indent_level -= TAB_SIZE; + indent(); + os << "]" << CRLF; +} + + +void json_reader::skip_whitespace() +{ + char c; + while (true) + { + int ic = is_.peek(); + if (ic == -1) + break; + if (is_whitespace((char)ic)) + { + c = get(); + } + else if (ic == '/') + { + get(); + int c2 = is_.peek(); + if (c2 == '/') { + // skip to end of line. + get(); + while (true) { + c2 = is_.peek(); + if (c2 == '\r' || c2 == '\n') + { + get(); // and continue. + break; + } + if (c2 == -1) + { + break; + } + get(); + } + } else if (c2 == '*') { + get(); + int level = 1; + while (true) + { + c = get(); + if (c == '*' && is_.peek() == '/') + { + get(); + if (--level == 0) + { + break; + } + } + if (c == '/' && is_.peek() == '*') + { + get(); + ++level; + } + } + } else { + + throw_format_error(); + } + } else + { + + break; + } + } +} + +std::string json_reader::read_string() +{ + // To completely normalize UTF-32 values we must covert to UTF-16, resolve surrogate pairs, and then convert UTF-32 to UTF-8. + + + skip_whitespace(); + char c; + char startingCharacter; + startingCharacter = get(); + if (startingCharacter != '\'' && startingCharacter != '\"') + { + throw_format_error(); + } + std::stringstream s; + + while (true) + { + c = get(); + if (c == startingCharacter) + { + if (is_.peek() == startingCharacter) // "" -> " + { + get(); + s.put(c); + } else { + break; + } + } + if (c != '\\') + { + s << (char)c; + } + else + { + c = get(); + switch (c) + { + case '"': + case '\\': + default: + s << c; + break; + case 'r': + s << '\r'; + break; + case 'b': + s << '\b'; + break; + case 'f': + s << '\f'; + break; + case 'n': + s << '\n'; + break; + case 't': + s << '\t'; + break; + case 'u': + { + uint32_t uc = read_u_escape(); + if (uc >= UTF16_SURROGATE_1_BASE && uc <= UTF16_SURROGATE_1_BASE + UTF16_SURROGATE_MASK) + { + // MUST be a UTF16_SURROGATE 2 to be legal. + c = get(); + if (c != '\\') + throw_format_error("Invalid UTF16 surrogate pair"); + c = get(); + if (c != 'u') + throw_format_error("Invalid UTF16 surrogate pair"); + uint16_t uc2 = read_u_escape(); + if (uc2 < UTF16_SURROGATE_2_BASE || uc2 > UTF16_SURROGATE_2_BASE + UTF16_SURROGATE_MASK) + { + throw_format_error("Invalid UTF16 surrogate pair"); + } + uc = ((uc & UTF16_SURROGATE_MASK) << 10) + (uc2 & UTF16_SURROGATE_MASK) + 0x10000U; + } + HtmlHelper::utf32_to_utf8_stream(s, uc); + } + break; + } + } + } + return s.str(); +} +uint16_t json_reader::read_hex() +{ + char c; + c = get(); + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + throw_format_error("Invalid \\u escape character"); + return 0; +} + +uint16_t json_reader::read_u_escape() +{ + uint16_t c1 = read_hex(); + uint16_t c2 = read_hex(); + uint16_t c3 = read_hex(); + uint16_t c4 = read_hex(); + + return (c1 << 12) + (c2 << 8) + (c3 << 4) + c4; +} + +bool json_reader::is_complete() +{ + skip_whitespace(); + return is_.peek() == -1; +} + +void json_reader::consumeToken(const char*expectedToken, const char*errorMessage) +{ + skip_whitespace(); + + const char*p = expectedToken; + while (*p != '\0') + { + char expectedChar = *p++; + int c = is_.get(); + if (expectedChar != c) { + this->throw_format_error(errorMessage); + } + } +} + +void json_reader::consume(char expected) +{ + skip_whitespace(); + char c; + c = get(); + if (c != expected) + { + std::stringstream s; + s << "Expecting '" << expected << "'"; + throw_format_error(s.str().c_str()); + } +} + +void json_reader::skip_property() +{ + skip_whitespace(); + int c = is_.peek(); + switch (c) + { + case '[': + skip_array(); + break; + case '{': + skip_object(); + break; + case '\"': + skip_string(); + break; + case 't': + case 'f': + read_boolean(); + break; + case 'n': + read_null(); + break; + default: + skip_number(); + break; + } +} +void json_reader::skip_string() +{ + consume('"'); + while (true) + { + char c; + c = get(); + if (c == '\"') + { + if (peek() == '\"') + { + get(); + } else { + break; + } + } + if (c == '\\') + { + c = get(); // all of standard escapes, enough to get past \u + } + } +} + +void json_reader::skip_number() +{ + skip_whitespace(); + char c; + while (true) + { + int ic = is_.peek(); + if (ic == -1) + break; + if (is_whitespace((char)ic)) + { + break; + } + c = get(); + } +} +void json_reader::skip_array() +{ + char c; + consume('['); + + while (true) + { + if (peek() == ']') + { + c = get(); + break; + } + skip_property(); + skip_whitespace(); + if (is_.peek() == ',') + { + c = get(); + } + } +} + +void json_reader::skip_object() +{ + char c; + consume('{'); + while (true) + { + if (peek() == '}') + { + c = get(); + break; + } + skip_string(); // name. + consume(':'); + skip_object(); + if (peek() == ',') + { + consume(','); + } + } +} + +void json_reader::read_object_start() +{ + skip_whitespace(); + + char c; + c = get(); + if (c != '{') + throw_format_error(); +} + +std::string json_reader::readToken() +{ + skip_whitespace(); + + std::stringstream s; + while (true) + { + int ic = is_.peek(); + if (ic == -1) + break; + char c = (char)ic; + if (!std::isalpha(c)) + break; + is_.get(); + s << c; + } + return s.str(); + +} + +void json_reader::read_null() +{ + std::string s = readToken(); + if (s != "null") + { + throw_format_error("Format error. Expecting 'null'."); + + } +} +bool json_reader::read_boolean() +{ + std::string ss = readToken(); + if (ss == "true") + return true; + if (ss == "false") + return false; + + throw_format_error("Format error. Expectiong 'true' or 'false'"); + return false; +} + +void json_reader::throw_format_error(const char*error) +{ + std::stringstream s; + s << error; + s << ", near: '"; + skip_whitespace(); + if (is_.peek() == -1) { + s << ""; + } else { + for (int i = 0; i < 40; ++i) + { + if (is_.peek()) break; + int c = get(); + if (c == -1) break; + if (c == '\r') { + s << "\\r"; + } else if (c == '\n') + { + s << "\\n"; + } else { + s << c; + } + } + } + s << "'."; + throw PiPedalException(s.str()); + +} diff --git a/src/json.hpp b/src/json.hpp new file mode 100644 index 0000000..d42cf4b --- /dev/null +++ b/src/json.hpp @@ -0,0 +1,829 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "HtmlHelper.hpp" +#include +#include "PiPedalException.hpp" + + + +#define DECLARE_JSON_MAP(CLASSNAME) \ + static json_map::storage_type jmap + +#define JSON_MAP_BEGIN(CLASSNAME) \ + json_map::storage_type CLASSNAME::jmap { { + +#define JSON_MAP_REFERENCE(class,name) \ + json_map::reference(#name,&class::name##_), + +#define JSON_MAP_REFERENCE_CONDITIONAL(class,name, conditionFn) \ + json_map::conditional_reference(#name,&class::name##_,conditionFn) , + + +#define JSON_MAP_END() \ +}}; + +namespace pipedal +{ + +// a function pointer of type bool (*)(const CLASS*,const MEMBER_TYPE&value) (because pre-C++ 20 templated function pointers are *hard*) +template class JsonConditionFunction { +public: + using Pointer = bool (*)(const CLASS*self,const MEMBER_TYPE&value); +}; + + +//---------------------------------------------------------------------------------- + + +class json_reader; +class json_writer; + +class JsonWritable { +public: + virtual void write_members(json_writer&writer) const = 0; +}; + +template +class json_member_reference_base { +private: + const char*name_; +protected: + json_member_reference_base(const char*name) + :name_(name) + { + } +public: + virtual ~json_member_reference_base() {} + const char*name() { return this->name_; } + virtual bool canWrite(const CLASS *self) { return true; } + virtual void read_value(json_reader&reader, CLASS*self) = 0; + virtual void write_value(json_writer&writer, const CLASS*self) = 0; +}; +template +class json_member_reference: public json_member_reference_base { +public: + virtual ~json_member_reference() {} + json_member_reference(const char*name, MEMBER_TYPE CLASS::*member_pointer) + : json_member_reference_base(name) + , member_pointer(member_pointer) + { + } + MEMBER_TYPE CLASS::*member_pointer; + + void read_value(json_reader&reader, CLASS*self); + void write_value(json_writer&writer, const CLASS*self); + + +}; +template +class json_conditional_member_reference: public json_member_reference_base { +public: + virtual ~json_conditional_member_reference() {} + + json_conditional_member_reference(const char*name, MEMBER_TYPE CLASS::*member_pointer,typename JsonConditionFunction::Pointer condition) + : json_member_reference_base(name) + , member_pointer(member_pointer) + , condition_(condition) + { + } + MEMBER_TYPE CLASS::*member_pointer; + + typename JsonConditionFunction::Pointer condition_; + + virtual bool canWrite(const CLASS *self); + + void read_value(json_reader&reader, CLASS*self); + void write_value(json_writer&writer, const CLASS*self); +}; + + + +template +class json_enum_converter { +public: + virtual CLASS fromString(const std::string&value) const = 0; + virtual const std::string& toString(CLASS value) const = 0; +}; + +template +class json_enum_member_reference: public json_member_reference_base { +public: + json_enum_member_reference(const char*name, MEMBER_TYPE CLASS::*member_pointer, const json_enum_converter*converter) + : json_member_reference_base(name) + , member_pointer(member_pointer) + , converter_(converter) + { + } + MEMBER_TYPE CLASS::*member_pointer; + const json_enum_converter *converter_; + + + void read_value(json_reader&reader, CLASS*self); + void write_value(json_writer&writer, const CLASS*self); + + +}; + + +//---------------------------------------------------------------------------------- +class json_map_base { + +}; + +template +class json_map_impl: public json_map_base { +private: + std::vector* > members_; + json_map_impl(const json_map_impl&) { } // disable copy constructor. +public: + json_map_impl(std::vector*> members) + : members_(members) + { + + } + virtual ~json_map_impl() + { + for (auto member: members_) + { + delete member; + } + members_.resize(0); + } + void read_property(json_reader* reader,const char*memberName,CLASS *pObject); + void write_members(json_writer* writer, const CLASS*pObject); + + +}; + + + +class json_map { +public: + template class storage_type : public json_map_impl { + public: + storage_type(std::vector*> members) + : json_map_impl(members) + { + } + }; + template + static json_member_reference * + reference(const char*name,MEMBER_TYPE CLASS::*member_pointer) + { + return new json_member_reference(name,member_pointer); + }; + template + static json_enum_member_reference * + enum_reference( + const char*name, + MEMBER_TYPE CLASS::*member_pointer, + const ENUM_CONVERTER*converter) + { + return new json_enum_member_reference(name,member_pointer,converter); + }; + + template + static json_conditional_member_reference * + conditional_reference(const char*name,MEMBER_TYPE CLASS::*member_pointer,typename JsonConditionFunction::Pointer condition ) + { + return new json_conditional_member_reference(name,member_pointer,condition); + }; + +}; + +//---------------------------------------------------------------------------------- + +template +class HasJsonPropertyMap { + + template + static std::true_type test (decltype(TYPE::jmap) *) { return std::true_type();}; + + template + static std::false_type test (...); + +public: + static constexpr bool value = decltype(test(nullptr))::value; +}; + + +//---------------------------------------------------------------------------------- + + + +class json_writer; + + +class json_writer { +public: + const char*CRLF; +private: + std::ostream &os; + int indent_level; + bool compressed; + const int TAB_SIZE = 2; + + const uint16_t UTF16_SURROGATE_1_BASE = 0xD800U; + const uint16_t UTF16_SURROGATE_2_BASE = 0xDC00U; + const uint16_t UTF16_SURROGATE_MASK = 0x3FFFU; + + static const uint32_t UTF8_ONE_BYTE_MASK = 0x80; + static const uint32_t UTF8_ONE_BYTE_BITS = 0; + static const uint32_t UTF8_TWO_BYTES_MASK = 0xE0; + static const uint32_t UTF8_TWO_BYTES_BITS = 0xC0; + static const uint32_t UTF8_THREE_BYTES_MASK = 0xF0; + static const uint32_t UTF8_THREE_BYTES_BITS = 0xE0; + static const uint32_t UTF8_FOUR_BYTES_MASK = 0xF8; + static const uint32_t UTF8_FOUR_BYTES_BITS = 0xF0; + static const uint32_t UTF8_CONTINUATION_MASK = 0xC0; + static const uint32_t UTF8_CONTINUATION_BITS = 0x80; + + +public: + void write_raw(const char*text) { + os << text; + } + using string_view = boost::string_view; + json_writer(std::ostream &os, bool compressed = false) + : os(os) + , compressed(compressed) + , indent_level(0) + { + this->CRLF = compressed? "" : "\r\n"; + } + void write(long value) + { + os << value; + } + void write(int64_t value) + { + os << value; + } + void write(uint64_t value) + { + os << value; + } + void write(int32_t value) + { + os << value; + } + void write(uint32_t value) + { + os << value; + } + + + +private: + static void throw_encoding_error(); + + static uint32_t continuation_byte(std::string_view::iterator &p, std::string_view::const_iterator end); + void write_utf16_char(uint16_t uc); + +public: + void indent(); + std::ostream & output_stream() { return os; } + + void write(bool value) { + os << (value? "true": "false"); + } + void write( + string_view v, + bool enforceValidUtf8 // throw errors for illegal (non-minimal) UTF-8 sequences. + ); + void write(string_view v) + { + write(v,true); + } + void write(const char*p) + { + write(string_view(p)); + } + + void write(const std::string&s) + { + write(string_view(s.c_str())); + } + void write(float f) + { + os << std::setprecision(std::numeric_limits::max_digits10) << f; // round-trip format + } + void write(double f) + { + os << std::setprecision(std::numeric_limits::max_digits10) << f; // round-trip format + } + + template void write(const std::vector &value) + { + if (std::is_fundamental() || std::is_assignable() || value.size() == 0) + { + // simple types: all on same line. + os << "[ "; + + if (value.size() >= 1) + { + write(value[0]); + } + for (int i = 1; i < value.size(); ++i) + { + os << ","; + write(value[i]); + } + os << "]"; + } else { + // complex types: one line per entry. + os << "[" << CRLF; + indent_level += TAB_SIZE; + bool first = true; + for (int i = 0; i < value.size(); ++i) + { + if (!first) + { + os << ',' << CRLF; + } + first = false; + indent(); + write(value[i]); + } + indent_level -= TAB_SIZE; + os << CRLF; + indent(); + os << "]"; + + } + } + template< + class Category, + class T, + class Distance = std::ptrdiff_t, + class Pointer = T*, + class Reference = T& + > void write(std::iterator &it) { + start_array(); + bool first = true; + for( Reference ref: it) + { + if (!first) + { + os << ", "; + os << CRLF; + } + indent(); + os << ref; + } + end_array(); + } + + void write_json_member(const char*name, const char*json_text) + { + write(name); + os << ": "; + os << json_text; + } + + template void write_member(const char*name,const T&value) + { + write(name); + os << ": "; + write(value); + } + void start_object(); + void end_object(); + void start_array(); + void end_array(); + + +/* + void write(const json_writable *obj) + { + if (obj == nullptr) + { + os << "null"; + } else { + start_object(); + obj->write(*this); + end_object(); + } + } + void write(const json_writable &obj) + { + start_object(); + obj.write(*this); + end_object(); + } +*/ +private: + template + json_map::storage_type& get_object_map() + { + //static_assert(HasJsonPropertyMap::value,"Type does not have a Json propery map name jmap."); + // Type T must have public static propery jmap. + return T::jmap; + } +public: + + void write(const JsonWritable*pWritable) + { + start_object(); + pWritable->write_members(*this); + end_object(); + } + template + void write(const std::shared_ptr &obj) + { + write(obj.get()); + } + template + void write(const std::weak_ptr &obj) + { + auto p = obj.lock(); + write(p.get()); + } + template + void write(const std::unique_ptr &obj) + { + write(obj.get()); + } + + template + void write(const T*obj) + { + static_assert(HasJsonPropertyMap::value,"Json serialization type not supported. (Json object classes must have a Json property map named jmap)."); + if (obj == nullptr) + { + write_raw("null"); + } else { + write(*obj); + } + + } + template + void write(T*obj) + { + static_assert(HasJsonPropertyMap::value,"Json serialization type not supported. (Json object classes must have a Json property map named jmap)."); + if (obj == nullptr) + { + write_raw("null"); + } else { + write(*obj); + } + + } + + template + void write(const T&obj) + { + static_assert(HasJsonPropertyMap::value,"Json serialization type not supported. (Json object classes must have a Json property map named jmap)."); + + auto &map = get_object_map(); + start_object(); + + map.write_members(this,&obj); + + end_object(); + } + + + + +}; + + +class json_reader { + std::istream &is_; + + const uint16_t UTF16_SURROGATE_1_BASE = 0xD800U; + const uint16_t UTF16_SURROGATE_2_BASE = 0xDC00U; + const uint16_t UTF16_SURROGATE_MASK = 0x3FFU; + + +public: + json_reader(std::istream &input) + : is_(input) + { + + } + +private: + void throw_format_error(const char*error); + + void throw_format_error() + { + throw_format_error("Invalid file format"); + } + + + + inline bool is_whitespace(char c) + { + switch (c) + { + case 0x20: + case 0x0A: + case 0x0D: + case 0x09: + return true; + default: + return false; + } + + } + char get() { + int ic = is_.get(); + if (ic == -1) throw_format_error("Unexpected end of file"); + return (char)ic; + } + + void skip_whitespace(); + + void read_object_start(); + uint16_t read_hex(); + uint16_t read_u_escape(); + + template + json_map::storage_type& get_object_map() + { + // Type T must have public static propery map. + return T::jmap; + } +public: + void consume(char expected); + void consumeToken(const char*expectedToken, const char*errorMessage); + int peek() + { + skip_whitespace(); + return is_.peek(); + } +public: + std::string read_string(); + +public: + bool is_complete(); + + template + void read(T*pObject) + { + char c; + consume('{'); + + auto &map = get_object_map(); + while (true) + { + c = peek(); + if (c == '}') + { + c = get(); + break; + } + std::string memberName = read_string(); + + consume(':'); + skip_whitespace(); + + map.read_property(this,memberName.c_str(),pObject); + + skip_whitespace(); + if (is_.peek() == ',') + { + c = get(); + } + } + } + template + void read(T**pObject) + { + int c = peek(); + if (c != '{') + { + if (c == 'n') + { + consumeToken("null", "Expecting '{' or 'null'."); + *pObject = nullptr; + return; + } + } + *pObject = new T(); + read(*pObject); + } + + template + void read(std::unique_ptr *pUniquePtr) + { + std::unique_ptr p = std::make_unique(); + + read(p.get()); + *pUniquePtr = std::move(p); + } + template + void read(std::shared_ptr *pUniquePtr) + { + std::shared_ptr p = std::make_shared(); + + read(p.get()); + (*pUniquePtr) = std::move(p); + } + template + void read(std::weak_ptr *pUniquePtr) + { + throw std::domain_error("Can't read std::weak_ptr"); + } + +private: + void skip_string(); + void skip_number(); + void skip_array(); + void skip_object(); + std::string readToken(); + bool read_boolean(); + void read_null(); + void skip_token(); +public: + void skip_property(); + + void read(std::string*value) { + skip_whitespace(); + *value = read_string(); + } + + void read(bool *value) + { + skip_whitespace(); + *value = read_boolean(); + } + void read(long*value) + { + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + void read(int32_t *value) { + skip_whitespace(); + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + void read(int64_t*value) { + skip_whitespace(); + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + void read(uint32_t *value) { + skip_whitespace(); + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + void read(uint64_t*value) { + skip_whitespace(); + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + + void read(float*value) { + skip_whitespace(); + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + void read(double*value) { + skip_whitespace(); + is_ >> *value; + if (is_.fail()) throw PiPedalException("Invalid format."); + } + template + void read(std::vector*value) + { + char c; + std::vector result; + + consume('['); + while (true) + { + if (peek() == ']') + { + c = get(); + break; + } + T item; + read(&item); + result.push_back(std::move(item)); + if (peek() == ',') + { + c = get(); + } + } + *value = std::move(result); + } + + +}; + +template +class HasJsonRead { + + + template + static std::true_type test (decltype(json_reader(std::cin).read((ARG*)nullptr))*v) { return std::true_type();}; + + template + static std::false_type test (...); + +public: + static constexpr bool value = decltype(test(nullptr))::value; +}; + + + +template +void json_member_reference::read_value(json_reader&reader, CLASS*self) { + static_assert(HasJsonRead::value,"Type not supported for Json serialization."); + MEMBER_TYPE *ref = &((*self).*member_pointer); + reader.read(ref); +} +template +void json_member_reference::write_value(json_writer&writer, const CLASS*self) { + const MEMBER_TYPE &ref = (*self).*member_pointer; + writer.write_member(this->name(),ref); +} + +template +void json_enum_member_reference::read_value(json_reader&reader, CLASS*self) { + MEMBER_TYPE *ref = &((*self).*member_pointer); + std::string val = reader.read_string(); + *ref = converter_->fromString(val); +} + +template +void json_enum_member_reference::write_value(json_writer&writer, const CLASS*self) { + const MEMBER_TYPE &ref = (*self).*member_pointer; + std::string val = converter_->toString(ref); + writer.write_member(this->name(),val); +} + + +template +void json_map_impl::read_property(json_reader* reader,const char*memberName,CLASS *pObject) +{ + for (json_member_reference_base*member: members_) + { + if (strcmp(member->name(),memberName) == 0) + { + member->read_value(*reader,pObject); + return; + } + + } + reader->skip_property(); +} + +template +void json_conditional_member_reference::read_value(json_reader&reader, CLASS*self) { + static_assert(HasJsonRead::value,"Type not supported for Json serialization."); + MEMBER_TYPE *ref = &((*self).*member_pointer); + reader.read(ref); +} + +template +bool json_conditional_member_reference::canWrite(const CLASS*self) { + const MEMBER_TYPE &ref = (*self).*member_pointer; + return this->condition_(self,ref); + +} + + +template +void json_conditional_member_reference::write_value(json_writer&writer, const CLASS*self) { + const MEMBER_TYPE &ref = (*self).*member_pointer; + writer.write_member(this->name(),ref); +} + + +template +void json_map_impl::write_members(json_writer* writer, const CLASS*pObject) +{ + bool first = true; + for (json_member_reference_base*member: members_) + { + if (member->canWrite(pObject)) + { + if (!first) + { + writer->output_stream() << ','; + writer->output_stream() << writer->CRLF; + } + first = false; + writer->indent(); + member->write_value(*writer,pObject); + } + } + +} + + + + + + +} // namespace pipedal \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..abdd06c --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,490 @@ +#include "pch.h" +#include "BeastServer.hpp" +#include +#include "Lv2Log.hpp" + +#include "PiPedalSocket.hpp" +#include "Lv2Host.hpp" +#include +#include +#include "PiPedalConfiguration.hpp" +#include "Shutdown.hpp" +#include "CommandLineParser.hpp" +#include "Lv2SystemdLogger.hpp" +#include +#include +#include "HtmlHelper.hpp" + +#include +#include + +using namespace pipedal; +using namespace boost::beast; + +#define PRESET_EXTENSION ".piPreset" +#define BANK_EXTENSION ".piBank" + +sem_t signalSemaphore; + +class application_category : public boost::system::error_category +{ +public: + const char *name() const noexcept { return "PiPedal"; } + std::string message(int ev) const { return "error message"; } +}; + +void sig_handler(int signo) +{ + sem_post(&signalSemaphore); +} +using namespace boost::system; + + +class DownloadIntercept : public RequestHandler +{ + PiPedalModel *model; + +public: + DownloadIntercept(PiPedalModel *model) + : RequestHandler("/var"), + model(model) + { + } + + virtual bool wants(boost::beast::http::verb verb, const uri &request_uri) const + { + if (request_uri.segment_count() != 2 || request_uri.segment(0) != "var") + { + return false; + } + if (request_uri.segment(1) == "downloadPreset") + { + std::string strInstanceId = request_uri.query("id"); + if (strInstanceId != "") + return true; + } + if (request_uri.segment(1) == "uploadPreset") + { + return true; + } + return false; + } + + + std::string GetContentDispositionHeader(const std::string &name, const std::string &extension) + { + std::string fileName = name.substr(0,64) + extension; + std::stringstream s; + + s << "attachment; filename*=" << HtmlHelper::Rfc5987EncodeFileName(fileName) << "; filename=\"" << HtmlHelper::SafeFileName(fileName) << "\""; + std::string result = s.str(); + return result; + } + + void GetPreset(const uri &request_uri, std::string *pName, std::string *pContent) + { + std::string strInstanceId = request_uri.query("id"); + int64_t instanceId = std::stol(strInstanceId); + auto pedalBoard = model->getPreset(instanceId); + + // a certain elegance to using same file format for banks and presets. + BankFile file; + file.name(pedalBoard.name()); + int64_t newInstanceId = file.addPreset(pedalBoard); + file.selectedPreset(newInstanceId); + + std::stringstream s; + json_writer writer(s); + writer.write(file); + *pContent = s.str(); + *pName = pedalBoard.name(); + } + + virtual void head_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + try + { + if (request_uri.segment(1) == "downloadPreset") + { + std::string name; + std::string content; + GetPreset(request_uri, &name, &content); + + res.set(http::field::content_type, "application/octet-stream"); + res.set(http::field::cache_control, "no-cache"); + res.set(http::field::content_length, content.length()); + res.set(http::field::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION)); + return; + } + throw PiPedalException("Not found."); + } + catch (const std::exception &e) + { + if (strcmp(e.what(), "Not found") == 0) + { + ec = boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory); + } + else + { + ec = boost::system::errc::make_error_code(boost::system::errc::invalid_argument); + } + } + } + + virtual void get_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + try + { + if (request_uri.segment(1) == "downloadPreset") + { + std::string name; + std::string content; + GetPreset(request_uri, &name, &content); + + res.set(http::field::content_type, "application/octet-stream"); + res.set(http::field::cache_control, "no-cache"); + res.set(http::field::content_length, content.length()); + res.set(http::field::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION)); + res.body() = content; + } + } + catch (const std::exception &e) + { + if (strcmp(e.what(), "Not found") == 0) + { + ec = boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory); + } + else + { + ec = boost::system::errc::make_error_code(boost::system::errc::invalid_argument); + } + } + } + virtual void post_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + try + { + if (request_uri.segment(1) == "uploadPreset") + { + std::string presetBody = req.body(); + std::stringstream s(presetBody); + json_reader reader(s); + + uint64_t uploadAfter = -1; + std::string strUploadAfter = request_uri.query("uploadAfter"); + if (strUploadAfter.length() != 0) + { + uploadAfter = std::stol(strUploadAfter); + } + + BankFile bankFile; + reader.read(&bankFile); + + uint64_t instanceId = model->uploadPreset(bankFile,uploadAfter); + + res.set(http::field::content_type, "application/json"); + res.set(http::field::cache_control, "no-cache"); + std::stringstream sResult; + sResult << instanceId; + std::string result = sResult.str(); + res.set(http::field::content_length, result.length()); + + res.body() = result; + } + } + catch (const std::exception &e) + { + if (strcmp(e.what(), "Not found") == 0) + { + ec = boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory); + } + else + { + ec = boost::system::errc::make_error_code(boost::system::errc::invalid_argument); + } + } + } + +}; + +/* When hosting a react app, replace /var/config.json with + data that will connect the react app with our socket server. +*/ + +class InterceptConfig : public RequestHandler +{ +private: + std::string response; + uint64_t maxUploadSize; + +public: + InterceptConfig(int portNumber,uint64_t maxUploadSize) + : RequestHandler("/var/config.json"), + maxUploadSize(maxUploadSize) + { + std::stringstream s; + + s << "{ \"socket_server_port\": " << portNumber + << ", \"socket_server_address\": \"*\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }"; + response = s.str(); + } + virtual ~InterceptConfig() {} + + virtual void head_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + res.set(http::field::content_type, "application/json"); + res.set(http::field::cache_control, "no-cache"); + res.content_length(response.length()); + return; + } + + virtual void get_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + res.set(http::field::content_type, "application/json"); + res.set(http::field::cache_control, "no-cache"); + res.content_length(response.length()); + res.body() = response; + } +}; + +class ReactRedirector : public RequestHandler +{ + PiPedalConfiguration config; + +public: + ReactRedirector(const PiPedalConfiguration &config) + : RequestHandler("/"), + config(config) + + { + } + virtual ~ReactRedirector() {} + + virtual bool wantsRedirect(const uri &requestUri) + { + if (requestUri.segment_count() == 0 || (requestUri.segment_count() == 1 && requestUri.segment(0) == "index.htm")) + { + return true; + } + return false; + } + uri GetRedirect(const uri &requestUri) + { + return requestUri; + } + + virtual bool wants(boost::beast::http::verb verb, const uri &request_uri) const + { + return false; + } + + virtual void head_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + ec = errc::make_error_code(errc::no_such_file_or_directory); + return; + } + + virtual void get_response( + const uri &request_uri, + const boost::beast::http::request &req, + boost::beast::http::response &res, + boost::beast::error_code &ec) + { + ec = errc::make_error_code(errc::no_such_file_or_directory); + } +}; + +uint16_t g_ShutdownPort = 0; + +int main(int argc, char *argv[]) +{ + sem_init(&signalSemaphore, 0, 0); + + signal(SIGINT, sig_handler); + +#ifndef WIN32 + umask(002); // newly created files in /var/pipedal get 775-ish permissions, which improves debugging/live-service interaction. +#endif + + // Check command line arguments. + bool help = false; + bool error = false; + bool systemd = false; + uint16_t shutdownPort = 0; + std::string portOption; + + CommandLineParser parser; + parser.AddOption("-h", &help); + parser.AddOption("--help", &help); + parser.AddOption("-systemd", &systemd); + parser.AddOption("-port", &portOption); + parser.AddOption("-shutdownPort", &shutdownPort); + + try + { + parser.Parse(argc, (const char **)argv); + if (parser.Arguments().size() > 2) + { + throw PiPedalException("Too many arguments."); + } + if (parser.Arguments().size() == 0) + { + throw PiPedalException(" not provided."); + } + if (help || parser.Arguments().size() == 0) + { + std::cout << "pipedald - Pipedal web socket server.\n" + "Copyright (c) 2021 Robin Davies.\n" + "\n"; + } + } + catch (const std::exception &e) + { + std::cout << "Error: " << e.what() << "\n\n"; + error = true; + help = true; + } + + if (help) + { + std::cout << "Usage: pipedal [] [options...]\n\n" + << "Options:\n" + << " -systemd: Log to systemd journals.\n" + << " -port: Port to listen on e.g. 0.0.0.0:80\n" + << " -shutdownPort: Port for the shutdown service.\n" + << "Example:\n" + << " pipedal /etc/pipedal/config /etc/pipedal/react -port 0.0.0.0:80 \n" + "\n" + "Description:\n\n" + " Configuration is read from /config.json\n" + "\n" + " If is not provided, pipedal will serve from \n" + "\n" + " While debugging, bind the port to 0.0.0.0:8080, and connect to the default React\n" + " server that's provided when you run 'npm run start' in 'react/src'. By default, the\n" + " React app will connect to the socket server on 0.0.0.0:8080.\n\n"; + return error ? EXIT_FAILURE : EXIT_SUCCESS; + } + + g_ShutdownPort = shutdownPort; + if (systemd) + { + Lv2Log::set_logger(MakeLv2SystemdLogger()); + } + signal(SIGTERM, sig_handler); + + std::filesystem::path doc_root = parser.Arguments()[0]; + std::filesystem::path web_root = doc_root; + if (parser.Arguments().size() >= 2) + { + web_root = parser.Arguments()[1]; + } + + PiPedalConfiguration configuration; + try + { + configuration.Load(doc_root); + } + catch (const std::exception &e) + { + std::stringstream s; + s << "Unable to read configuration from '" << (doc_root / "config.json") << "'. (" << e.what() << ")"; + Lv2Log::error(s.str()); + return EXIT_FAILURE; + } + + Lv2Log::log_level(configuration.GetLogLevel()); + + if (portOption.length() != 0) + { + configuration.SetSocketServerEndpoint(portOption); + } + + uint16_t port; + std::shared_ptr server; + try + { + auto const address = boost::asio::ip::make_address(configuration.GetSocketServerAddress()); + port = static_cast(configuration.GetSocketServerPort()); + + auto const threads = std::max(1, configuration.GetThreads()); + + server = std::make_shared( + address, port, web_root.c_str(), threads); + + Lv2Log::info("Document root: %s Threads: %d", doc_root.c_str(), (int)threads); + + server->SetLogHttpRequests(configuration.LogHttpRequests()); + + boost::asio::ip::network_v4 gateway; + if (configuration.GetAccessPointGateway(&gateway)) + { + server->SetAccessPointGateway(gateway, configuration.GetAccessPointServerAddress()); + } + } + catch (const std::exception &e) + { + std::stringstream s; + s << "Fatal error: " << e.what() << std::endl; + Lv2Log::error(s.str()); + return EXIT_FAILURE; + } + + try + { + PiPedalModel model; + + model.Load(configuration); + + auto pipedalSocketFactory = MakePiPedalSocketFactory(model); + + server->AddSocketFactory(pipedalSocketFactory); + + std::shared_ptr interceptConfig{new InterceptConfig(port,configuration.GetMaxUploadSize())}; + server->AddRequestHandler(interceptConfig); + + std::shared_ptr downloadIntercept = std::make_shared(&model); + server->AddRequestHandler(downloadIntercept); + + server->RunInBackground(); + + sem_wait(&signalSemaphore); + + Lv2Log::info("Shutting down gracefully."); + model.Close(); + Lv2Log::info("Stopping web server."); + server->Stop(); + server->Join(); + Lv2Log::info("Shutdown complete."); + } + catch (const std::exception &e) + { + Lv2Log::error(e.what()); + } + Lv2Log::info("PiPedal terminating."); + return EXIT_FAILURE; // only exit in response to a signal. +} diff --git a/src/pch.h b/src/pch.h new file mode 100644 index 0000000..4b2ce28 --- /dev/null +++ b/src/pch.h @@ -0,0 +1,36 @@ +#pragma once + +// Diagnostic type used to report calculated type T in an error message. +template class TypeDisplay; + + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +// #include +#include "lv2/atom/atom.h" +#include "lv2/atom/util.h" +#include "lv2/core/lv2.h" +#include "lv2/core/lv2_util.h" +#include "lv2/log/log.h" +#include "lv2/log/logger.h" +#include "lv2/midi/midi.h" +#include "lv2/urid/urid.h" +#include "lv2/log/logger.h" +#include "lv2/uri-map/uri-map.h" +#include "lv2/atom/forge.h" +#include "lv2/worker/worker.h" +#include "lv2/patch/patch.h" +#include "lv2/parameters/parameters.h" +#include "lv2/units/units.h" +#include diff --git a/src/template.service b/src/template.service new file mode 100644 index 0000000..811855b --- /dev/null +++ b/src/template.service @@ -0,0 +1,23 @@ +[Unit] +Description=${DESCRIPTION} +After=jack.service +After=network.target +BindsTo=jack.service + + +[Service] +LimitMEMLOCK=infinity +LimitRTPRIO=95 +ExecStart=${COMMAND} +User=pipedal_d +Group=pipedal_d +Restart=always +RestartSec=15 +TimeoutStopSec=10 +WorkingDirectory=/var/pipedal +Environment=JACK_PROMISCUOUS_SERVER=jack +Environment=JACK_START_SERVER=1 + + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/src/templateShutdown.service b/src/templateShutdown.service new file mode 100644 index 0000000..6e64288 --- /dev/null +++ b/src/templateShutdown.service @@ -0,0 +1,13 @@ +[Unit] +Description=${DESCRIPTION} +After=network.target + +[Service] +ExecStart=${COMMAND} +Restart=always +RestartSec=60 +WorkingDirectory=/var/pipedal + + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/src/viewstream.hpp b/src/viewstream.hpp new file mode 100644 index 0000000..80d3c48 --- /dev/null +++ b/src/viewstream.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include +#include +#include +#include + +template +class view_streambuf final: public std::basic_streambuf<__char_type, __traits_type > { +private: + typedef std::basic_streambuf<__char_type, __traits_type > super_type; + typedef view_streambuf<__char_type, __traits_type> self_type; +public: + + /** + * These are standard types. They permit a standardized way of + * referring to names of (or names dependent on) the template + * parameters, which are specific to the implementation. + */ + typedef typename super_type::char_type char_type; + typedef typename super_type::traits_type traits_type; + typedef typename traits_type::int_type int_type; + typedef typename traits_type::pos_type pos_type; + typedef typename traits_type::off_type off_type; + + typedef typename std::basic_string_view source_view; + + view_streambuf(const source_view& src) noexcept: + super_type(), + src_( src ) + { + char_type *buff = const_cast( src_.data() ); + this->setg( buff , buff, buff + src_.length() ); + } + + virtual std::streamsize xsgetn(char_type* __s, std::streamsize __n) override + { + if(0 == __n) + return 0; + if( (this->gptr() + __n) >= this->egptr() ) { + __n = this->egptr() - this->gptr(); + if(0 == __n && !traits_type::not_eof( this->underflow() ) ) + return -1; + } + std::memmove( static_cast(__s), this->gptr(), __n); + this->gbump( static_cast(__n) ); + return __n; + } + + virtual int_type pbackfail(int_type __c) override + { + char_type *pos = this->gptr() - 1; + *pos = traits_type::to_char_type( __c ); + this->pbump(-1); + return 1; + } + + virtual int_type underflow() override + { + return traits_type::eof(); + } + + virtual std::streamsize showmanyc() override + { + return static_cast( this->egptr() - this->gptr() ); + } + + virtual ~view_streambuf() override + {} +private: + const source_view& src_; +}; + +template +class view_istream final:public std::basic_istream<_char_type, std::char_traits<_char_type> > { + view_istream(const view_istream&) = delete; + view_istream& operator=(const view_istream&) = delete; +private: + typedef std::basic_istream<_char_type, std::char_traits<_char_type> > super_type; + typedef view_streambuf<_char_type, std::char_traits<_char_type> > streambuf_type; +public: + typedef _char_type char_type; + typedef typename super_type::int_type int_type; + typedef typename super_type::pos_type pos_type; + typedef typename super_type::off_type off_type; + typedef typename super_type::traits_type traits_type; + typedef typename streambuf_type::source_view source_view; + + view_istream(const source_view& src): + super_type( nullptr ), + sb_(nullptr) + { + sb_ = new streambuf_type(src); + this->init( sb_ ); + } + + + view_istream(view_istream&& other) noexcept: + super_type( std::forward(other) ), + sb_( std::move( other.sb_ ) ) + {} + + view_istream& operator=(view_istream&& rhs) noexcept + { + view_istream( std::forward(rhs) ).swap( *this ); + return *this; + } + + virtual ~view_istream() override { + delete sb_; + } + +private: + streambuf_type *sb_; +}; + diff --git a/test/BeastServerTest.cpp b/test/BeastServerTest.cpp new file mode 100644 index 0000000..9b63c96 --- /dev/null +++ b/test/BeastServerTest.cpp @@ -0,0 +1,24 @@ +#include "pch.h" +#include "catch.hpp" + + +#include "BeastServer.hpp" + +using namespace piddle; + +TEST_CASE( "BeastServer shutodwn", "[beastServerShutdown]" ) { + + auto const address = boost::asio::ip::make_address("0.0.0.0"); + auto const port = 8081; + std::string doc_root = "/bad"; + auto const threads = 3; + + auto server = std::make_shared( + address,port,doc_root.c_str(),threads); + server->RunInBackground(); + sleep(3); + server->Stop(); + server->Join(); + +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..119c11d --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,80 @@ +cmake_minimum_required(VERSION 3.19.0) +project(piddletest VERSION 0.1.0) + + +# specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set (CMAKE_CXX_FLAGS "-Wno-psabi -fsanitize=address -static-libasan") + +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}") + + +include(CTest) +enable_testing() + + + + +include(FindPkgConfig) + + +pkg_check_modules(SYSTEMD "systemd") +if(!SYSTEMD_FOUND) + message(ERROR "libsystemd-dev package not installed.") +else() + message(STATUS "SYSTEMD_LIBRARIES: ${SYSTEMD_LIBRARIES}") + message(STATUS "SYSTEMD_INCLUDE_DIRS: ${SYSTEMD_INCLUDE_DIRS}") +endif() + + +pkg_check_modules(LILV_0 "lilv-0") +if(!LILV_0_FOUND) + message(ERROR "lilv-0 package not installed.") +else() + message(STATUS "LILV_0_LIBRARIES: ${LILV_0_LIBRARIES}") + message(STATUS "LILV_0_INCLUDE_DIRS: ${LILV_0_INCLUDE_DIRS}") +endif() + +pkg_check_modules(JACK "jack") + +add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY) +add_executable(piddletest main.cpp pch.h UriTest.cpp JsonTest.cpp + + + ../src/Uri.cpp ../src/Uri.hpp ../src/HtmlHelper.cpp ../src/HtmlHelper.hpp BeastServerTest.cpp + ../src/BeastServer.cpp ../src/BeastServer.hpp ../src/json.hpp ../src/json.cpp + ../src/Lv2Host.cpp ../src/Lv2Host.hpp + ../src/Lv2Log.hpp ../src/Lv2Log.cpp + ../src/PluginType.hpp ../src/PluginType.cpp + ../src/Lv2Effect.hpp ../src/Lv2Effect.cpp + ../src/Lv2PedalBoard.hpp ../src/Lv2PedalBoard.cpp + + ../src/MapFeature.hpp ../src/MapFeature.cpp + ../src/LogFeature.hpp ../src/LogFeature.cpp + ../src/Worker.hpp ../src/Worker.cpp + ../src/OptionsFeature.hpp ../src/OptionsFeature.cpp + ../src/asan_options.cpp + + ../src/Units.hpp ../src/Units.cpp + + + Lv2Test.cpp + + ) +target_precompile_headers(piddletest PRIVATE pch.h + ) +target_link_libraries(piddletest PUBLIC + pthread atomic + ${LILV_0_LIBRARIES} + ${JACK_LIBRARIES} + ${SYSTEMD_LIBRARIES} + ) + +target_include_directories(piddletest PRIVATE + ${LILV_0_INCLUDE_DIRS} ${JACK_INCLUDE_DIRS} ${SYSTEMD_INCLUDE_DIRS} + "../src" + ) + +#target_link_libraries(Piddle boost_system) + diff --git a/test/JsonTest.cpp b/test/JsonTest.cpp new file mode 100644 index 0000000..c394aa2 --- /dev/null +++ b/test/JsonTest.cpp @@ -0,0 +1,150 @@ +#include "pch.h" +#include "catch.hpp" +#include +#include +#include + + +#include + +using namespace piddle; + +class JsonTestTarget { +private: + JsonTestTarget(const JsonTestTarget&) {} // hide copy constructor. + JsonTestTarget& operator=(const JsonTestTarget&) { return *this;} // hide assignment. +public: + JsonTestTarget() // make sure reading works without a default cosntructor. + { + } + bool operator==(const JsonTestTarget &other) const + { + return this->int_ == other.int_ + && this->float_ == other.float_ + && this->double_ == other.double_ + && this->string_ == other.string_ + && std::equal(this->ints_.begin(),this->ints_.end(), other.ints_.begin(),other.ints_.end()) + && std::equal(this->strings_.begin(),this->strings_.end(), other.strings_.begin(),other.strings_.end()) + ; + + } +public: + int int_ = 1; + float float_ = 3; + double double_ = 4; + +public: + std::string string_{"5"}; + + std::vector ints_ { 1,2,3,4,5}; + std::vector strings_ { "a","b","c","d"}; + std::vector > compound_array_ { { 1,2},{3},{4,5,6},{9}}; + +public: + static json_map::storage_type jmap; + + +public: + JsonTestTarget(json_reader& reader) + { + #ifdef JUNK + while (true) + { + const char*name = reader.read_member_name(); + if (name == nullptr) + { + break; + } + } + #endif + } + +}; + +json_map::storage_type JsonTestTarget::jmap {{ + //json_map::reference("char_", &JsonTestTarget::char_), + json_map::reference("int", &JsonTestTarget::int_), + json_map::reference("floatt", &JsonTestTarget::float_), + json_map::reference("double", &JsonTestTarget::double_), + json_map::reference("ints", &JsonTestTarget::ints_), + json_map::reference("string", &JsonTestTarget::string_), + json_map::reference("strings", &JsonTestTarget::strings_), + json_map::reference("compoundarray", &JsonTestTarget::compound_array_), +}}; + + + +TEST_CASE( "json write", "[json_write_test]" ) { + std::stringstream os; + json_writer writer { os }; + + JsonTestTarget testTarget; + + writer.write(testTarget); + + std::cout << os.str(); +} + +static std::string get_json() +{ + std::stringstream os; + json_writer writer { os }; + + JsonTestTarget testTarget; + + writer.write(testTarget); + return os.str(); + +} + + +TEST_CASE( "json read", "[json_read_test]" ) { + + JsonTestTarget source; + source.ints_ = { 1,7,4}; + source.string_ = "xyz"; + source.double_ = 99483.1837; + + std::stringstream os; + json_writer writer(os); + writer.write(source); + std::string json = os.str(); + + std::stringstream input (json); + json_reader reader { input }; + + JsonTestTarget dest; + reader.read(&dest); + REQUIRE(reader.is_complete()); + + REQUIRE( source == dest); + + + JsonTestTarget *pDest; + std::stringstream input2(json); + json_reader reader2 { input2}; + reader2.read(&pDest); + + + //JsonTestTarget *testTarget = reader.read_object(); + +} + +TEST_CASE( "json smart ptrs", "[json_smart_ptrs]" ) { + std::string json =get_json(); + + + { + std::unique_ptr uniquePtr; + std::stringstream input(json); + json_reader reader { input }; + reader.read(&uniquePtr); + } + { + std::shared_ptr sharedPtr; + std::stringstream input(json); + json_reader reader { input }; + reader.read(&sharedPtr); + } + +} \ No newline at end of file diff --git a/test/Lv2Test.cpp b/test/Lv2Test.cpp new file mode 100644 index 0000000..2ea1b3b --- /dev/null +++ b/test/Lv2Test.cpp @@ -0,0 +1,50 @@ +#include "pch.h" +#include "catch.hpp" +#include +#include "Lv2Host.hpp" + +using namespace piddle; + +TEST_CASE( "Lv2 Plugins", "[lv2_plugins]" ) { + + Lv2Host lv2Host; + + lv2Host.Load(); + + + { + json_writer writer (std::cerr); + writer.write((lv2Host.GetPlugins())); + } + + +} + +TEST_CASE( "Lv2 UI Plugins", "[lv2_ui_plugins]" ) { + + Lv2Host lv2Host; + + lv2Host.Load(); + + { + json_writer writer (std::cerr); + writer.write((lv2Host.GetUiPlugins())); + } + + +} + +TEST_CASE( "Lv2 Classes Plugins", "[lv2_classes]" ) { + + Lv2Host lv2Host; + + lv2Host.Load(); + + auto rootPlugin = lv2Host.GetLv2PluginClass(); + { + json_writer writer (std::cerr); + writer.write(rootPlugin); + } + + +} \ No newline at end of file diff --git a/test/UriTest.cpp b/test/UriTest.cpp new file mode 100644 index 0000000..47b9fab --- /dev/null +++ b/test/UriTest.cpp @@ -0,0 +1,85 @@ +#include "pch.h" +#include "catch.hpp" +#include +#include + +using namespace piddle; + +TEST_CASE( "uri test", "[uri]" ) { + + uri t("http://user@authority/path?q1=1&q2=2#fragment"); + + REQUIRE( t.scheme() == std::string("http") ); + REQUIRE( t.user() == std::string("user") ); + REQUIRE( t.authority() == std::string("authority") ); + REQUIRE( t.path() == std::string("/path") ); + + REQUIRE( t.segment_count() == 1); + REQUIRE( t.segment(0) == std::string("path") ); + REQUIRE( t.is_relative() == false ); + REQUIRE( t.fragment() == std::string("fragment") ); + + REQUIRE( t.query_count() == 2); + REQUIRE( t.query("q1") == "1"); + REQUIRE( t.query("q2") == "2"); + REQUIRE( t.query("q3") == ""); + + REQUIRE( t.query(0) == query_segment("q1","1")); + REQUIRE( t.query(1) == query_segment("q2","2")); + + t.set("/"); + REQUIRE( t.scheme() == "" ); + REQUIRE( t.user() == ""); + REQUIRE( t.authority() == ""); + REQUIRE( t.path() == std::string("/") ); + + REQUIRE( t.segment_count() == 0); + REQUIRE( t.is_relative() == false ); + REQUIRE( t.fragment() == ""); + + REQUIRE( t.query_count() == 0); + REQUIRE( t.query("q1") == ""); + + t.set(""); + REQUIRE( t.scheme() == "" ); + REQUIRE( t.user() == ""); + REQUIRE( t.authority() == ""); + REQUIRE( t.path() == std::string("") ); + + REQUIRE( t.segment_count() == 0); + REQUIRE( t.is_relative() == true ); + REQUIRE( t.fragment() == ""); + + REQUIRE( t.query_count() == 0); + REQUIRE( t.query("q1") == ""); + + t.set("a"); + REQUIRE( t.scheme() == "" ); + REQUIRE( t.user() == ""); + REQUIRE( t.authority() == ""); + REQUIRE( t.path() == std::string("a") ); + + REQUIRE( t.segment_count() == 1); + REQUIRE( t.segment(0) == "a"); + REQUIRE( t.is_relative() == true ); + REQUIRE( t.fragment() == ""); + + REQUIRE( t.query_count() == 0); + REQUIRE( t.query("q1") == ""); + + t.set("a/b#c"); + REQUIRE( t.is_relative() == true); + REQUIRE( t.segment_count() == 2); + REQUIRE( t.segment(0) == "a"); + REQUIRE( t.segment(1) == "b"); + REQUIRE( t.fragment() == "c"); + + t.set("/a/b#c"); + REQUIRE( t.is_relative() == false); + REQUIRE( t.segment_count() == 2); + REQUIRE( t.segment(0) == "a"); + REQUIRE( t.segment(1) == "b"); + REQUIRE( t.fragment() == "c"); + + +} \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..95b3503 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,4 @@ +#include "pch.h" +#define CATCH_CONFIG_MAIN +#include + diff --git a/test/pch.h b/test/pch.h new file mode 100644 index 0000000..50b9d3a --- /dev/null +++ b/test/pch.h @@ -0,0 +1,18 @@ +#pragma once + +// Diagnostic type used to report calculated type T in an error message. +template class TypeDisplay; + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..9f1811a --- /dev/null +++ b/todo.txt @@ -0,0 +1,68 @@ +Features: + + +Patches. + +8 Updload/download patches. +9 Upload/download banks. + + + - have to make sure it's set in the USER's environment. + +10 Test missing plugin handling. +10 Handle 12TET and Midi control types, trigger types. + + +7 Popless loading of presets. 10hz hipass? +4 Bypass view? + +4 Midi Bindings. +3 OpenSound wire control protocol bindings. + + + +Bugs: + +Delete bank confirmation. + +Deal with aftermath of config. :-/ +pulseaudio --kill + +Reconnect of controls after config change. + + +Layout of 2nd and subsequent splits. + +Crash when changing input channels to mono. + +frequency response is routed to both instances of ToobInput. Did we fail to detect the instanceID change? + +scrollto fix for Load Dialog. + + +Access Point: must disable wpa_supplicant when running Access Point. + + +Config issues: + +Build: cmake was installed by code. :-/ Package hell. + +Open source copyrights. + +10 JACK_PROMISCUOUS_SERVER -- must be set in all user environments. Create jack group, add JACK_PROMISCUOUS_SERVER to jackd. RTPriority for Jack? + +10 Wireless host. dnsmasq configuration. + +add pipedal.local to etc/hosts. + + + + + + + + + + + + diff --git a/uninstall b/uninstall new file mode 100755 index 0000000..bf3a5ae --- /dev/null +++ b/uninstall @@ -0,0 +1,5 @@ +export PREFIX=/usr/local + +rm $PREFIX/bin/pipedal*.* +rm -rf /etc/pipedal/ +