diff --git a/.gitignore b/.gitignore index db0688c2ef..f94c928650 100644 --- a/.gitignore +++ b/.gitignore @@ -306,6 +306,9 @@ paket-files/ __pycache__/ *.pyc +# Python Virtual environments +*__venv/ + # Cake - Uncomment if you are using it # tools/** # !tools/packages.config @@ -365,6 +368,8 @@ src/ProjectTemplates/Quantum.Test1/.template.config/template.json src/QsCompiler/QirGeneration/QirGeneration.nuspec /examples/QIR/Development/qir/* /examples/QIR/Development/build +src/Telemetry/Tests/coverage.json +src/Telemetry/.vscode/settings.json # MSBuild logs MSBuild_Logs/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..00444125a3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "src/Passes/vendors/googletest"] + path = src/Passes/vendors/googletest + url = https://github.com/google/googletest.git + shallow = true diff --git a/build/build.ps1 b/build/build.ps1 index 0f9c3fe9e3..2cedce4613 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -142,6 +142,7 @@ $all_ok = $True Build-One '../QsCompiler.sln' Build-One '../examples/QIR/QIR.sln' Build-One '../src/QuantumSdk/Tools/Tools.sln' +Build-One '../src/Telemetry/Telemetry.sln' Build-One '../QsFmt.sln' if ($Env:ENABLE_VSIX -ne "false") { diff --git a/build/ci.yml b/build/ci.yml index c679045f59..c3645fa39c 100644 --- a/build/ci.yml +++ b/build/ci.yml @@ -26,8 +26,6 @@ schedules: - main always: true -pool: - vmImage: windows-latest jobs: - job: Build @@ -35,6 +33,20 @@ jobs: - template: init.yml - template: steps.yml - template: wrap-up.yml + pool: + vmImage: windows-latest + +- job: LinuxBuild + steps: + - template: passes-linux.yml + pool: + vmImage: ubuntu-20.04 + +- job: MacOSBuild + steps: + - template: passes-mac.yml + pool: + vmImage: macOS-latest - job: Style steps: @@ -43,3 +55,5 @@ jobs: - script: dotnet tool run fantomas -- --check --recurse . displayName: Fantomas + pool: + vmImage: windows-latest diff --git a/build/init.yml b/build/init.yml index 5c0c420205..3cfa7a428e 100644 --- a/build/init.yml +++ b/build/init.yml @@ -31,3 +31,4 @@ steps: inputs: command: 'custom' customCommand: 'install -g npm@latest' + diff --git a/build/passes-linux.yml b/build/passes-linux.yml new file mode 100644 index 0000000000..43265056a8 --- /dev/null +++ b/build/passes-linux.yml @@ -0,0 +1,24 @@ + +steps: +- script: | + export DEBIAN_FRONTEND=noninteractive + sudo apt-get update -y + sudo apt-get install -y + sudo apt-get remove -y llvm-12 + sudo apt-get install -y curl pkg-config findutils wget + sudo apt install -y clang-11 cmake clang-format-11 clang-tidy-11 + sudo apt-get install -y llvm-11 lldb-11 llvm-11-dev libllvm11 llvm-11-runtime + sudo apt install -y python3 python3-pip + sudo apt-get remove -y llvm-10 + sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 0 + git submodule update --init --recursive + cd src/Passes/ + pip install -r requirements.txt + chmod +x manage + export PYTHONUNBUFFERED=1 + export PYTHON_BIN_PATH=/usr/bin/python3 + export CC=clang-11 + export CXX=clang++-11 + ./manage runci + + displayName: Linux build and CI for passes diff --git a/build/passes-mac.yml b/build/passes-mac.yml new file mode 100644 index 0000000000..f045019b12 --- /dev/null +++ b/build/passes-mac.yml @@ -0,0 +1,22 @@ + +steps: +- script: | + rm '/usr/local/bin/2to3' + brew install llvm@11 + brew install cmake + brew install python@3.9 + brew unlink python@3.9 + brew link python@3.9 + + # Updating paths + export PATH="/usr/local/opt/python/libexec/bin:$PATH" + export PATH="/usr/local/opt/llvm@11/bin:$PATH" + export LDFLAGS="${LDFLAGS} -L/usr/local/opt/llvm@11/lib" + export CPPFLAGS="${CPPFLAGS} -I/usr/local/opt/llvm@11/include" + + git submodule update --init --recursive + cd src/Passes/ + pip3 install --user -r requirements.txt + chmod +x manage + ./manage --loglevel info runci + diff --git a/build/set-env.ps1 b/build/set-env.ps1 index d2529951b5..b62830d2aa 100644 --- a/build/set-env.ps1 +++ b/build/set-env.ps1 @@ -5,6 +5,11 @@ $ErrorActionPreference = 'Stop' Write-Host "Setting up build environment variables" +# Enable the QDK Telemetry Library to throw exceptions +# This is useful to capture unexpected unhandled exceptions as we +# test telemetry-related code +$env:ENABLE_QDK_TELEMETRY_EXCEPTIONS = "1" + If ($Env:BUILD_CONFIGURATION -eq $null) { $Env:BUILD_CONFIGURATION ="Debug" } If ($Env:BUILD_VERBOSITY -eq $null) { $Env:BUILD_VERBOSITY ="m" } If ($Env:ASSEMBLY_VERSION -eq $null) { $Env:ASSEMBLY_VERSION ="0.0.1.0" } diff --git a/build/steps.yml b/build/steps.yml index cd530df6be..c81dce5f0c 100644 --- a/build/steps.yml +++ b/build/steps.yml @@ -1,4 +1,5 @@ steps: + - pwsh: ./build.ps1 displayName: "Build all" workingDirectory: $(System.DefaultWorkingDirectory)/build diff --git a/build/test.ps1 b/build/test.ps1 index adfd20f7e5..68d95a87f0 100644 --- a/build/test.ps1 +++ b/build/test.ps1 @@ -38,7 +38,9 @@ function Test-One { } } + Test-One '../QsCompiler.sln' +Test-One '../src/Telemetry/Telemetry.sln' Test-One '../QsFmt.sln' if (-not $all_ok) { diff --git a/examples/QIR/Development/Development.csproj b/examples/QIR/Development/Development.csproj index 477f3f323a..74493b8648 100644 --- a/examples/QIR/Development/Development.csproj +++ b/examples/QIR/Development/Development.csproj @@ -1,4 +1,4 @@ - + Exe @@ -20,8 +20,8 @@ - - + + @@ -136,6 +136,7 @@ <_QirRuntimeLibFiles Include="$(QirRuntimeLibs)/**/*.*" Exclude="$(QirRuntimeLibs)/**/*.exe" /> <_QirRuntimeHeaderFiles Include="$(QirRuntimeHeaders)/**/*.hpp" /> + <_QirRuntimeHeaderFiles Include="$(QirRuntimeHeaders)/**/*.h" /> diff --git a/examples/QIR/Emission/Emission.csproj b/examples/QIR/Emission/Emission.csproj index 7f8829fd9a..7e1c497226 100644 --- a/examples/QIR/Emission/Emission.csproj +++ b/examples/QIR/Emission/Emission.csproj @@ -1,4 +1,4 @@ - + Detailed diff --git a/src/Passes/.clang-format b/src/Passes/.clang-format new file mode 100644 index 0000000000..379a41ff3c --- /dev/null +++ b/src/Passes/.clang-format @@ -0,0 +1,69 @@ +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html + +--- +Language: Cpp +BasedOnStyle: Microsoft + +# page width +ColumnLimit: 120 +ReflowComments: true + +# tabs and indents +UseTab: Never +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: -2 +NamespaceIndentation: Inner + +# line and statements layout +BreakBeforeBraces: Allman +BinPackParameters: false +AlignAfterOpenBracket: AlwaysBreak +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortFunctionsOnASingleLine: Empty +AllowAllConstructorInitializersOnNextLine: false +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma + +# misc +Cpp11BracedListStyle: true +FixNamespaceComments: true +IncludeBlocks: Preserve +SpaceBeforeInheritanceColon : true +SpaceBeforeParens: ControlStatements +DerivePointerAlignment: false +PointerAlignment: Left + +# Suggestions +Standard: Cpp11 +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignTrailingComments: true + +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 + +IndentCaseLabels: false +# NamespaceIndentation: None + +# Ensures include compleness +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '.*\.\..*' + Priority: 1 + - Regex: '^<.*\.h.*>$' + Priority: 5 + - Regex: '^<.*>$' + Priority: 6 + - Regex: '^"(llvm)/.*"$' + Priority: 4 + - Regex: '.*/.*' + Priority: 3 + - Regex: '.*' + Priority: 2 +IncludeIsMainRegex: '' +SortIncludes: true +SortUsingDeclarations: true +SpaceInEmptyParentheses: false diff --git a/src/Passes/.clang-tidy b/src/Passes/.clang-tidy new file mode 100644 index 0000000000..9265e6feab --- /dev/null +++ b/src/Passes/.clang-tidy @@ -0,0 +1,105 @@ +Checks: "-*,bugprone-*,\ +-readability-*,\ +readability-identifier-*,\ +readability-redundant-member-init,\ +readability-braces-around-statements,\ +cert-dcl*,\ +cert-env*,\ +cert-err52-cpp,\ +cert-err60-cpp,\ +cert-flp30-c,\ +clang-analyzer-*,\ +clang-analyzer-security.FloatLoopCounter,\ +google-build-explicit-make-pair,\ +google-build-namespaces,\ +google-explicit-constructor,\ +google-readability-*,\ +google-runtime-operator,\ +hicpp-exception-baseclass,\ +hicpp-explicit-conversions,\ +hicpp-use-*,\ +modernize-avoid-bind,\ +modernize-loop-convert,\ +modernize-make-shared,\ +modernize-make-unique,\ +modernize-redundant-void-arg,\ +modernize-replace-random-shuffle,\ +modernize-shrink-to-fit,\ +modernize-use-bool-literals,\ +modernize-use-default-member-init,\ +modernize-use-emplace,\ +modernize-use-equals-default,\ +modernize-use-equals-delete,\ +modernize-use-noexcept,\ +modernize-use-nullptr,\ +modernize-use-override,\ +modernize-use-transparent-functors,\ +misc-*,\ +-misc-misplaced-widening-cast,\ +-misc-no-recursion,\ +performance-*" + +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' + +CheckOptions: + # Configuration documentation: https://clang.llvm.org/extra/clang-tidy/checks/readability-identifier-naming.html + # Namespaces + - key: readability-identifier-naming.NamespaceCase + value: 'lower_case' + + # Classes and structs + - key: readability-identifier-naming.AbstractClassPrefix + value: 'I' + - key: readability-identifier-naming.ClassCase + value: 'CamelCase' + - key: readability-identifier-naming.StructCase + value: 'CamelCase' + - key: readability-identifier-naming.UnionCase + value: 'CamelCase' + + # Class members + - key: readability-identifier-naming.PrivateMemberCase + value: 'lower_case' + - key: readability-identifier-naming.PrivateMemberSuffix + value: '_' + - key: readability-identifier-naming.ProtectedMemberCase + value: 'lower_case' + - key: readability-identifier-naming.ProtectedMemberSuffix + value: '_' + + # Type Alias and Enum Types / constants + - key: readability-identifier-naming.TypeAliasCase + value: 'CamelCase' + - key: readability-identifier-naming.TypedefCase + value: 'CamelCase' + - key: readability-identifier-naming.EnumCase + value: 'CamelCase' + - key: readability-identifier-naming.EnumConstantCase + value: 'CamelCase' + + # Globals, consts and enums + - key: readability-identifier-naming.GlobalConstantCase + value: 'UPPER_CASE' + - key: readability-identifier-naming.GlobalConstantPrefix + value: 'G_' + - key: readability-identifier-naming.ConstantCase + value: 'UPPER_CASE' + + # Functions + - key: readability-identifier-naming.FunctionCase + value: 'camelBack' + - key: readability-identifier-naming.IgnoreMainLikeFunctions + value: true + + # Variables and parameters + - key: readability-identifier-naming.VariableCase + value: 'lower_case' + - key: readability-identifier-naming.LocalVariableCase + value: 'lower_case' + - key: readability-identifier-naming.ParameterCase + value: 'lower_case' + + # Macros + - key: readability-identifier-naming.MacroDefinitionCase + value: 'UPPER_CASE' diff --git a/src/Passes/.dockerignore b/src/Passes/.dockerignore new file mode 100644 index 0000000000..c023cf8a5e --- /dev/null +++ b/src/Passes/.dockerignore @@ -0,0 +1,2 @@ +Debug/ +**_env/ diff --git a/src/Passes/CMakeLists.txt b/src/Passes/CMakeLists.txt new file mode 100644 index 0000000000..d50117d73e --- /dev/null +++ b/src/Passes/CMakeLists.txt @@ -0,0 +1,117 @@ +cmake_minimum_required(VERSION 3.4.3) + +project(QirPasses) +set(CMAKE_BUILD_TYPE "Debug") +option(MICROSOFT_ENABLE_TESTS "Enable test targets" ON) +option(MICROSOFT_ENABLE_DYNAMIC_LOADING "Use dynamic loading" ON) +option(MICROSOFT_GENERATE_COVERAGE "Generate coverage" OFF) + +# Microsoft Settings +set(MICROSOFT_ROOT_PASSES_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(MICROSOFT_ROOT_VENDOR_DIR ${MICROSOFT_ROOT_PASSES_DIR}/vendors) +message(STATUS "Passes dir: ${MICROSOFT_ROOT_PASSES_DIR}") +message(STATUS "Vendor dir: ${MICROSOFT_ROOT_VENDOR_DIR}") + +find_package(LLVM REQUIRED CONFIG) +include(CheckCXXCompilerFlag) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address,undefined -g -O0 -fno-sanitize-recover=all") +set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address,undefined -g -O0 -fno-sanitize-recover=all") +set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-omit-frame-pointer -fsanitize=address,undefined -g -O3 -fno-sanitize-recover=all") +set (CMAKE_LINKER_FLAGS_RELEASE "${CMAKE_LINKER_FLAGS_RELEASE} -fno-omit-frame-pointer -fsanitize=address,undefined -g -O3 -fno-sanitize-recover=all") + +# -fvisibility-inlines-hidden is set when building LLVM and on Darwin warnings +# are triggered if the passes library is built without this flag (though otherwise it +# builds fine). For consistency, add it here too. +check_cxx_compiler_flag("-fvisibility-inlines-hidden" SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG) +if(${SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG}) + if (${SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG} STREQUAL "1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden") + endif() +endif() + + +# Helper variable to determine if we are using clang compiler +set(using_clang_compiler FALSE) +if ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(using_clang_compiler TRUE) +endif () + +# Add compiler flags if we are +if (MICROSOFT_GENERATE_COVERAGE) + message(STATUS "Generating coverage data") + + if (using_clang_compiler) + # Generating coverage output + set(CMAKE_CXX_FLAGS_DEBUG "-g -fprofile-instr-generate -fcoverage-mapping -O0") + + # Forcing debug build + set(CMAKE_BUILD_TYPE "Debug") + else () + message(SEND_ERROR "Coverage flag enabled but clang compiler not found, CMake will exit.") + endif () +endif (MICROSOFT_GENERATE_COVERAGE) + + + +if(MICROSOFT_ENABLE_TESTS) + add_subdirectory(${MICROSOFT_ROOT_VENDOR_DIR}/googletest) + target_compile_options(gmock + INTERFACE + -Wno-everything) + target_compile_options(gtest + INTERFACE + -Wno-everything) + +endif(MICROSOFT_ENABLE_TESTS) + + +# Setting the standard configuration for the C++ compiler +# Rather than allowing C++17, we restrict ourselves to +# C++14 as this is the standard currently used by the LLVM +# project for compilation of the framework. While there is +# a very small chance that the difference in standard +# would break things, it is a possibility nonetheless. +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Weverything -Wconversion -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-padded -Wno-exit-time-destructors -Wno-global-constructors") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wno-documentation-unknown-command") + +include(${MICROSOFT_ROOT_PASSES_DIR}/cmake/Testing.cmake) +include(${MICROSOFT_ROOT_PASSES_DIR}/cmake/Library.cmake) + + + + +# LLVM is normally built without RTTI. Be consistent with that. +if(NOT LLVM_ENABLE_RTTI) + message(STATUS "RTTI is off") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +else() + message(STATUS "RTTI is on") +endif() + + +# We export the compile commands which are needed by clang-tidy +# to run the static analysis +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Adding LLVM include directories. We may choose +# to move this to a module level at a later point +include_directories(${LLVM_INCLUDE_DIRS}) +link_directories(${LLVM_LIBRARY_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +include_directories(${CMAKE_SOURCE_DIR}/Source) +llvm_map_components_to_libnames(llvm_libs support core irreader passes orcjit x86asmparser x86codegen x86desc x86disassembler x86info interpreter objcarcopts) + +message(STATUS "${llvm_libs}") + + +# Adding the libraries +add_subdirectory(Source) + +add_subdirectory(ComponentExamples) diff --git a/src/Passes/CONTRIBUTING.md b/src/Passes/CONTRIBUTING.md new file mode 100644 index 0000000000..68633dfe53 --- /dev/null +++ b/src/Passes/CONTRIBUTING.md @@ -0,0 +1,85 @@ +# Contributing + +This document sets out some light requirements for contributing to QAT. In case you do not feel like reading this style guide, just run + +```sh +./manage runci +``` + +from the `src/Passes` directory before making a pull request. This script enforces all requirements described below programmatically. You can then refer to this guide for an explanation for why and how. + +## Why do we need a style guide? + +Consistency and readability such that it is easy to read and understand code that was not written by yourself. For example, if one developer uses `CamelCase` for namespaces and `snake_case` for classes while another uses `snake_case` for namespaces and `CamelCase` you may end up with code sections that looks like this + +```cpp +int32_t main() +{ + name_space1::Class1 hello; + NameSpace2::class_name world; +} +``` + +which is hard to read. + +## What does the style guide apply to? + +The style guide applies to any new code written as well as code that is being refactored added to the `Passes` library. We do not rewrite existing code for the sake just changing the style. + +## Style discrepancy + +In case of a discrepancy between this guideline and `clang-tidy` or `clang-format`, +clang tools rule. In case of discrepancy between this guide and any guides subsequently referenced guides, this guide rules. However, feel free to suggest changes. Changes will be incorporated on the basis +that updated styles are apply to new code and not existing code. + +## Naming + +Naming is taken from the [Microsoft AirSim](https://github.com/microsoft/AirSim/blob/master/docs/coding_guidelines.md) project. + +| **Code Element** | **Style** | **Comment** | +| ------------------------ | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| Namespace | snake_case | Differentiates `namespace::ClassName` and `ClassName::SubClass` names | +| Class name | CamelCase | To differentiate from STL types which ISO recommends (do not use "C" or "T" prefixes) | +| Type aliases | CamelCase | To differentiate from STL types which ISO recommends | +| Template type parameters | CamelCase | To differentiate from STL types which ISO recommends | +| Function name | camelCase | Lower case start is almost universal except for .NET world | +| Parameters/Locals | snake_case | Vast majority of standards recommends this because \_ is more readable to C++ crowd (although not much to Java/.NET crowd) | +| Member variables | snake_case_with\_ | The prefix \_ is heavily discouraged as ISO has rules around reserving \_identifiers, so we recommend suffix instead | +| Enums and its members | CamelCase | Most except very old standards agree with this one | +| Globals | g_snake_case | Avoid using globals whenever possible, but if you have to use `g_`. | +| Constants | UPPER_CASE | Very contentious and we just have to pick one here, unless if is a private constant in class or method, then use naming for Members or Locals | +| File names | Match case of class name in file | Lot of pro and cons either way but this removes inconsistency in auto generated code (important for ROS) | + +## Modernise when possible + +In general, modernise the code where possible. For instance, prefer `using` over `typedef`. + +## Header guards + +Prefer `#pragma once` over `#ifdef` protection. + +## Code TODOs must contain owner name or Github issue + +```sh +./manage runci +(...) +Passes/src/OpsCounter/OpsCounter.cpp:39:21: error: missing username/bug in TODO [google-readability-todo,-warnings-as-errors] + // TODO: Fails to load if this is present + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // TODO(tfr): Fails to load if this is present +``` + +## Always add copyrights + +Always add copyrights at the top of the file. + +```text +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +``` + +For header files, prefer to put `#prama once` before the copyright. + +## Tabs vs. spaces + +We indent with 2 spaces. Nested namespaces are not indented. diff --git a/src/Passes/ComponentExamples/CArrayMap/main.cpp b/src/Passes/ComponentExamples/CArrayMap/main.cpp new file mode 100644 index 0000000000..21bbff8571 --- /dev/null +++ b/src/Passes/ComponentExamples/CArrayMap/main.cpp @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Generators/ProfileGenerator.hpp" +#include "Llvm/Llvm.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/RuleSet.hpp" +#include "TransformationRulesPass/TransformationRulesPass.hpp" + +using namespace microsoft::quantum; + +extern "C" void loadComponent(ProfileGenerator *generator); +void activateAllocatorReplacement(RuleSet &ruleset); +void removeArrayCopies(RuleSet &ruleset); +void replaceAccess(RuleSet &ruleset); + +class CArrayMapConfig +{ +public: + using String = std::string; + + void setup(ConfigurationManager &config) + { + config.setSectionName("CArrayMap", "Transformations to enable C-style array allocation."); + config.addParameter(replace_allocators_, "replace-allocators", + "Replace allocators with C++ allocators."); + + config.addParameter(remove_array_copies_, "remove-array-copies", + "Remove all array copies and replace them with the original array."); + + config.addParameter(repalce_access_operators_, "replace-access-operators", + "Assumes that allocators use continuous memory."); + } + + bool removeArrayCopies() const + { + return remove_array_copies_; + } + + bool replaceAccess() const + { + return repalce_access_operators_; + } + + bool replaceAllocators() const + { + return replace_allocators_; + } + +private: + bool replace_allocators_{true}; + bool remove_array_copies_{true}; + bool repalce_access_operators_{true}; +}; + +void activateAllocatorReplacement(RuleSet &ruleset) +{ + + using namespace microsoft::quantum::notation; + auto replacer = [](ReplacementRule::Builder &builder, ReplacementRule::Value *val, + ReplacementRule::Captures & captures, + ReplacementRule::Replacements &replacements) { + auto instr = llvm::dyn_cast(val); + + if (instr == nullptr) + { + return false; + } + + auto size_cst = llvm::dyn_cast(captures["size"]); + if (size_cst == nullptr) + { + return false; + } + + auto element_count = captures["count"]; + if (element_count == nullptr) + { + return false; + } + + builder.SetInsertPoint(instr->getNextNode()); + + // dest_type === + auto sext = builder.CreateSExt(size_cst, element_count->getType()); + auto total_size = builder.CreateNSWMul(element_count, sext); + + auto module = instr->getModule(); + auto function = module->getFunction("_Znam"); + + std::vector arguments; + arguments.push_back(total_size); + + if (!function) + { + std::vector types; + types.resize(arguments.size()); + for (uint64_t i = 0; i < types.size(); ++i) + { + types[i] = arguments[i]->getType(); + } + + auto return_type = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(val->getContext())); + + llvm::FunctionType *fnc_type = llvm::FunctionType::get(return_type, types, false); + function = llvm::Function::Create(fnc_type, llvm::Function::ExternalLinkage, "_Znam", module); + } + + auto new_allocator_call = builder.CreateCall(function, arguments); + auto bitcast = builder.CreateBitCast(new_allocator_call, instr->getType()); + + instr->replaceAllUsesWith(bitcast); + + replacements.push_back({llvm::dyn_cast(val), nullptr}); + return true; + }; + + ruleset.addRule( + {call("__quantum__rt__array_create_1d", "size"_cap = _, "count"_cap = _), replacer}); +} + +void replaceAccess(RuleSet &ruleset) +{ + + using namespace microsoft::quantum::notation; + auto replacer = [](ReplacementRule::Builder &builder, ReplacementRule::Value *val, + ReplacementRule::Captures & captures, + ReplacementRule::Replacements &replacements) { + auto instr = llvm::dyn_cast(val); + if (instr == nullptr) + { + return false; + } + + auto size_cst = llvm::dyn_cast(captures["size"]); + if (size_cst == nullptr) + { + return false; + } + + auto index = llvm::dyn_cast(captures["index"]); + if (index == nullptr) + { + return false; + } + + auto i8typeptr = llvm::dyn_cast(val->getType()); + if (i8typeptr == nullptr) + { + return false; + } + + builder.SetInsertPoint(instr->getNextNode()); + auto array = captures["array"]; + + auto i8array_ptr = builder.CreateBitCast(array, i8typeptr); + auto sext = builder.CreateSExt(size_cst, index->getType()); + auto position = builder.CreateNSWMul(index, sext); + auto element = builder.CreateInBoundsGEP(i8typeptr->getElementType(), i8array_ptr, position); + + instr->replaceAllUsesWith(element); + + replacements.push_back({instr, nullptr}); + return true; + }; + + ruleset.addRule( + {call("__quantum__rt__array_get_element_ptr_1d", + "array"_cap = call("__quantum__rt__array_create_1d", "size"_cap = _, "count"_cap = _), + "index"_cap = _), + replacer}); + + ruleset.addRule( + {callByNameOnly("__quantum__rt__array_update_reference_count"), deleteInstruction()}); + ruleset.addRule({callByNameOnly("__quantum__rt__array_update_alias_count"), deleteInstruction()}); +} + +void removeArrayCopies(RuleSet &ruleset) +{ + using namespace microsoft::quantum::notation; + auto replacer = [](ReplacementRule::Builder &, ReplacementRule::Value *val, + ReplacementRule::Captures & captures, + ReplacementRule::Replacements &replacements) { + auto instr = llvm::dyn_cast(val); + if (instr == nullptr) + { + return false; + } + + auto orig_array = llvm::dyn_cast(captures["array"]); + if (orig_array == nullptr) + { + return false; + } + + instr->replaceAllUsesWith(orig_array); + + replacements.push_back({llvm::dyn_cast(val), nullptr}); + return true; + }; + + ruleset.addRule({call("__quantum__rt__array_copy", "array"_cap = _, _), replacer}); +} + +extern "C" void loadComponent(ProfileGenerator *generator) +{ + generator->registerProfileComponent( + "c-array-map", [](CArrayMapConfig const &cfg, ProfileGenerator *ptr, Profile &profile) { + auto &ret = ptr->modulePassManager(); + + if (cfg.removeArrayCopies()) + { + RuleSet rule_set; + removeArrayCopies(rule_set); + auto config = TransformationRulesPassConfiguration::createDisabled(); + ret.addPass(TransformationRulesPass(std::move(rule_set), config, &profile)); + } + + if (cfg.replaceAccess()) + { + RuleSet rule_set; + replaceAccess(rule_set); + auto config = TransformationRulesPassConfiguration::createDisabled(); + ret.addPass(TransformationRulesPass(std::move(rule_set), config, &profile)); + } + + if (cfg.replaceAllocators()) + { + RuleSet rule_set; + activateAllocatorReplacement(rule_set); + auto config = TransformationRulesPassConfiguration::createDisabled(); + ret.addPass(TransformationRulesPass(std::move(rule_set), config, &profile)); + } + }); +} diff --git a/src/Passes/ComponentExamples/CMakeLists.txt b/src/Passes/ComponentExamples/CMakeLists.txt new file mode 100644 index 0000000000..299658bb33 --- /dev/null +++ b/src/Passes/ComponentExamples/CMakeLists.txt @@ -0,0 +1,41 @@ +add_library(HelloWorld SHARED HelloWorld/main.cpp) + +if (WIN32) + # Windows specific configure + # TODO(tfr): Add Windows specific configuration +elseif (APPLE) + target_link_libraries(HelloWorld + PUBLIC "$<$:-undefined dynamic_lookup>") +else () + target_compile_options(HelloWorld + PUBLIC "-fPIC") +endif () + + +add_library(InlinePassComponent SHARED InlinePassComponent/main.cpp) + +if (WIN32) + # Windows specific configure + # TODO(tfr): Add Windows specific configuration +elseif (APPLE) + target_link_libraries(InlinePassComponent + PUBLIC "$<$:-undefined dynamic_lookup>") +else () + target_compile_options(InlinePassComponent + PUBLIC "-fPIC") +endif () + + + +add_library(CArrayMap SHARED CArrayMap/main.cpp) + +if (WIN32) + # Windows specific configure + # TODO(tfr): Add Windows specific configuration +elseif (APPLE) + target_link_libraries(CArrayMap + PUBLIC "$<$:-undefined dynamic_lookup>") +else () + target_compile_options(CArrayMap + PUBLIC "-fPIC") +endif () \ No newline at end of file diff --git a/src/Passes/ComponentExamples/HelloWorld/main.cpp b/src/Passes/ComponentExamples/HelloWorld/main.cpp new file mode 100644 index 0000000000..3971de7a73 --- /dev/null +++ b/src/Passes/ComponentExamples/HelloWorld/main.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Generators/ProfileGenerator.hpp" +using namespace microsoft::quantum; + +extern "C" void loadComponent(ProfileGenerator *generator); + +class HelloWorldConfig +{ +public: + using String = std::string; + + void setup(ConfigurationManager &config) + { + config.setSectionName("Hello world configuration", + "Demonstration configuration for building a component boilerplate."); + config.addParameter(message_, "message", + "Message which is printed when setting the component up."); + } + + String message() const + { + return message_; + } + +private: + String message_{"Hello world"}; +}; + +extern "C" void loadComponent(ProfileGenerator *generator) +{ + generator->registerProfileComponent( + "hello-world", + [](HelloWorldConfig const &cfg, ProfileGenerator * /*ptr*/, Profile & /*profile*/) { + std::cout << "Message: " << cfg.message() << std::endl; + }); +} diff --git a/src/Passes/ComponentExamples/InlinePassComponent/main.cpp b/src/Passes/ComponentExamples/InlinePassComponent/main.cpp new file mode 100644 index 0000000000..d1eaa25196 --- /dev/null +++ b/src/Passes/ComponentExamples/InlinePassComponent/main.cpp @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Generators/ProfileGenerator.hpp" +using namespace microsoft::quantum; + +extern "C" void loadComponent(ProfileGenerator *generator); + +class InlinerConfig +{ +public: + using String = std::string; + + void setup(ConfigurationManager &config) + { + config.setSectionName("Inliner component", "Adds the LLVM Always Inline Pass to the profile"); + config.addParameter(inline_, "custom-inliner", "Activating the custom inliner."); + } + + bool shouldInline() const + { + return inline_; + } + +private: + bool inline_{false}; ///< Default behaviour is that we do not add the inliner pass +}; + +extern "C" void loadComponent(ProfileGenerator *generator) +{ + generator->registerProfileComponent( + "inliner", [](InlinerConfig const &cfg, ProfileGenerator *ptr, Profile & /*profile*/) { + if (cfg.shouldInline()) + { + auto &module_pass_manager = ptr->modulePassManager(); + + // Adds the inline pipeline + auto &pass_builder = ptr->passBuilder(); + auto inliner_pass = pass_builder.buildInlinerPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None, ptr->isDebugMode()); + module_pass_manager.addPass(std::move(inliner_pass)); + } + }); +} diff --git a/src/Passes/Docker/CI.Ubuntu20.dockerfile b/src/Passes/Docker/CI.Ubuntu20.dockerfile new file mode 100644 index 0000000000..95e8b57b8d --- /dev/null +++ b/src/Passes/Docker/CI.Ubuntu20.dockerfile @@ -0,0 +1,37 @@ +FROM ubuntu:20.04 + +# basic dependencies - +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update -y && \ + apt-get install -y + +RUN apt-get install -y curl \ + pkg-config \ + findutils \ + wget + +# build dependencies +RUN apt install -y clang-11 cmake clang-format-11 clang-tidy-11 && \ + apt-get install -y llvm-11 lldb-11 llvm-11-dev libllvm11 llvm-11-runtime && \ + export CC=clang-11 && \ + export CXX=clang++ + +# Python +RUN apt install -y python3 python3-pip && \ + update-alternatives --install /usr/bin/python python /usr/bin/python3 0 + +ADD . /src/ +RUN cd /src/ && \ + pip install -r requirements.txt && \ + chmod +x manage + +# running the build +ENV CC=clang-11 \ + CXX=clang++-11 \ + PYTHONUNBUFFERED=1 \ + PYTHON_BIN_PATH=/usr/bin/python3 + +WORKDIR /src/ +ENV export CC=clang-11 \ + export CXX=clang++-11 + diff --git a/src/Passes/Docker/Docs.dockerfile b/src/Passes/Docker/Docs.dockerfile new file mode 100644 index 0000000000..a5c5f1f143 --- /dev/null +++ b/src/Passes/Docker/Docs.dockerfile @@ -0,0 +1,47 @@ +########################## +# Generator +########################## +FROM ubuntu:20.04 as generator + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update -y && \ + apt-get install -y + +RUN apt-get install -y curl \ + pkg-config \ + findutils \ + wget \ + unzip doxygen + +RUN wget https://github.com/matusnovak/doxybook2/releases/download/v1.3.6/doxybook2-linux-amd64-v1.3.6.zip && \ + unzip doxybook2-linux-amd64-v1.3.6.zip + +ADD Source/ /build/Source/ +ADD doxygen.cfg /build/ + +ADD docs/ /build/docs/ + +WORKDIR /build/ +RUN doxygen doxygen.cfg && \ + doxybook2 --input Doxygen/xml --config docs/.doxybook/config.json --output docs/src/ && \ + rm -rf docs/src/Namespaces/namespace_0d* + +########################## +# Builder +########################## +FROM node:alpine as builder + +RUN mkdir /src/ +COPY --from=generator /build/docs/ /docs/ + +WORKDIR /docs/ +RUN yarn install && yarn build + + +########################## +# Documentation +########################## +FROM nginx:latest as documentation +ADD docs/nginx/default.conf /etc/nginx/conf.d/default.conf + +COPY --from=builder /docs/src/.vuepress/dist/ /usr/share/nginx/html diff --git a/src/Passes/Makefile b/src/Passes/Makefile new file mode 100644 index 0000000000..b5ff0156a6 --- /dev/null +++ b/src/Passes/Makefile @@ -0,0 +1,32 @@ +nothing: + @echo "Preventing the user from accidentality running the first command." + +documentation: + docker build -f Docker/Docs.dockerfile -t qir-passes-docs:latest . + +documentation-shell: documentation + docker run --rm -i -t qir-passes-docs:latest sh + +serve-docs: documentation + docker run -it --rm -p 8080:80 --name qir-documentation -t qir-passes-docs:latest + +doxygen: + doxygen doxygen.cfg + + +linux-docker: + docker build --no-cache -f Docker/CI.Ubuntu20.dockerfile -t qir-passes-ubuntu:latest . + +linux-ci: linux-docker + docker run -it --rm -t qir-passes-ubuntu:latest ./manage runci + +test-examples: + # Run all examples and verify that the output is a valid IR + cd QirExamples && make all + +clean: + rm -rf Release/ + rm -rf Debug/ + find . | grep ".profraw" | xargs rm + cd QirExamples && make clean + diff --git a/src/Passes/README.md b/src/Passes/README.md new file mode 100644 index 0000000000..46c7fd3dce --- /dev/null +++ b/src/Passes/README.md @@ -0,0 +1,50 @@ +# QIR Passes + +This document contains a brief introduction on how to use the QIR passes. A more comprehensive [walk-through is found here](./docs/src/index.md). + +## Building + +To build the tool, create a new build directory and switch to that directory: + +```sh +mkdir Debug +cd Debug/ +``` + +To build the library, first configure CMake from the build directory + +```sh +cmake .. +``` + +and then make your target + +```sh +make qat +``` + +For full instructions on dependencies and how to build, follow [these instructions](./docs/src/UserGuide/BuildingLibrary.md). + +## Getting started + +Once the project is built (see next sections), you can transform a QIR according to a profile as follows: + +```sh +./Source/Apps/qat --generate --profile base -S path/to/example.ll +``` + +Likewise, you can validate that a QIR follows a specification by running (Note, not implemented yet): + +```sh +./Source/Apps/qat --validate --profile base -S path/to/example.ll +``` + +## Documentation + +Most of the documentation is available [directly on Github](./docs/src/index.md). If you need API documentation, you can build and run it by typing + +```sh +make serve-docs +``` + +in the root folder of the passes directory. diff --git a/src/Passes/Source/AllocationManager/AllocationManager.cpp b/src/Passes/Source/AllocationManager/AllocationManager.cpp new file mode 100644 index 0000000000..34fceca882 --- /dev/null +++ b/src/Passes/Source/AllocationManager/AllocationManager.cpp @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/AllocationManager.hpp" + +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + BasicAllocationManager::BasicAllocationManagerPtr BasicAllocationManager::createNew() + { + BasicAllocationManagerPtr ret; + ret.reset(new BasicAllocationManager()); + + return ret; + } + + BasicAllocationManager::Index BasicAllocationManager::allocate(String const& name, Index const& count) + { + auto ret = next_qubit_index_; + + // Creating a memory segment mapping in case we are dealing with qubits + AllocatedMemoryBlock map; + map.name = name; + map.count = count; + + map.start = next_qubit_index_; + + // Advancing start + next_qubit_index_ += count; + map.end = map.start + count; + + mappings_.emplace_back(std::move(map)); + + // Advancing the allocation index + ++allocation_index_; + + updateRegistersInUse(allocationsInUse() + count); + + return ret; + } + + void BasicAllocationManager::release(Address const& address) + { + --allocation_index_; + auto it = mappings_.begin(); + + // Finding the element. Note that we could implement binary + // search but assume that we are dealing with few allocations + while (it != mappings_.end() && it->start != address) + { + ++it; + } + + if (it == mappings_.end()) + { + throw std::runtime_error("Qubit segment not found."); + } + + if (!reuse_qubits_) + { + mappings_.erase(it); + } + else + { + if (it->count > allocationsInUse()) + { + throw std::runtime_error("Attempting to release more qubits than what is currently allocated."); + } + + // In case we are reusing registers, we update how many we are currently using + updateRegistersInUse(allocationsInUse() - it->count); + + mappings_.erase(it); + + // Updating the next qubit index with naive algorithm that guarantees + // 1. Continuous allocation + // 2. No overlap in address + if (mappings_.empty()) + { + next_qubit_index_ = 0; + } + else + { + auto& b = mappings_.back(); + next_qubit_index_ = b.end; + } + } + } + + void BasicAllocationManager::setReuseRegisters(bool val) + { + reuse_qubits_ = val; + } + + void BasicAllocationManager::reset() + { + updateRegistersInUse(0); + mappings_.clear(); + allocation_index_ = 0; + next_qubit_index_ = 0; + } +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/AllocationManager/AllocationManager.hpp b/src/Passes/Source/AllocationManager/AllocationManager.hpp new file mode 100644 index 0000000000..f4a79612e3 --- /dev/null +++ b/src/Passes/Source/AllocationManager/AllocationManager.hpp @@ -0,0 +1,110 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/IAllocationManager.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + /// AllocationManager is a simple qubit and results allocator that can be used at compile-time. + /// It is based on an assumption that all qubit allocating function calls are inlined and that + /// qubits/results can be allocated with strictly growing IDs. + class BasicAllocationManager : public IAllocationManager + { + public: + /// Defines a named register/memory address segment with start + /// position, end position and count. We think of the address space + /// as a continuous sequence of spaces that can store values and we + /// refer to a bounded continuous sequence memory addresses as a + /// segment (or memory address segment): + /// + /// start end + /// │ │ + /// ▼ ▼ + /// ┌ ─ ─ ─ ─ ─ ─ ─ + /// ┌ ─ ─ ┬ ─ ─ ┬─────┬─────┐ ┌─────┼ ─ ─ ┬ ─ ─ ┐ + /// 0 1 │ 2 │ 3 │... │ N+1 │ N+2 N+3 + /// └ ─ ─ ┴ ─ ─ ┴─────┴─────┘ └─────┴ ─ ─ ┴ ─ ─ ┘ + /// Address │ + /// space │ Memory address + /// segment + /// of N elements │ + /// └ ─ ─ ─ ─ ─ ─ ─ + /// + struct AllocatedMemoryBlock + { + String name{""}; ///< Name of the segment, if any given + Index count{0}; ///< Number of elements contained within memory address segment + Address start{0}; ///< Start address of memory address segment + Address end{0}; ///< End address (not included in memory address segment) + }; + + using Mappings = std::vector; ///< Vector of memory segments + using BasicAllocationManagerPtr = std::shared_ptr; ///< Allocator pointer type + + // Construction only allowed using smart pointer allocation through static functions. + // Constructors are private to prevent + // + + /// Creates a new allocation manager. The manager is kept + /// as a shared pointer to enable allocation across different + /// passes and/or replacement rules. + static BasicAllocationManagerPtr createNew(); + + // Allocation and release functions + // + + /// Allocates a possibly named segment of a given count. Calling allocate without and + /// arguments allocates a single anonymous resource and returns the address. In case + /// of a larger segment, the function returns the address pointing to the first element. + /// Allocation is guaranteed to be sequential. + Address allocate(String const& name = "", Index const& count = 1) override; + + /// Releases the segment by address. + void release(Address const& address) override; + + /// Resets the allocation manager and all its statistics + void reset() override; + + /// Configuration function to set mode of qubit allocation. If function argument is true, + /// the allocation manager will reuse qubits. + void setReuseRegisters(bool val); + + private: + // Private constructors + // + + /// Public construction of this object is only allowed + /// as a shared pointer. To create a new AllocationManager, + /// use AllocationManager::createNew(). + BasicAllocationManager() = default; + + /// Variable to keep track of the next qubit to be allocated. + Index next_qubit_index_{0}; + + // Memory mapping + // + + /// Each allocation has a register/memory mapping which + /// keeps track of the allocation index, the segment count + /// and its name (if any). + Mappings mappings_{}; + Index allocation_index_{0}; + + // Configuration + // + + bool reuse_qubits_{true}; ///< Whether or not to reuse qubits + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/AllocationManager/IAllocationManager.cpp b/src/Passes/Source/AllocationManager/IAllocationManager.cpp new file mode 100644 index 0000000000..3e1011a20f --- /dev/null +++ b/src/Passes/Source/AllocationManager/IAllocationManager.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/IAllocationManager.hpp" + +namespace microsoft +{ +namespace quantum +{ + + IAllocationManager::~IAllocationManager() = default; + + uint64_t IAllocationManager::allocationsInUse() const + { + return registers_in_use_; + } + + uint64_t IAllocationManager::maxAllocationsUsed() const + { + return max_registers_used_; + } + + void IAllocationManager::updateRegistersInUse(uint64_t n) + { + registers_in_use_ = n; + if (n > max_registers_used_) + { + max_registers_used_ = n; + } + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/AllocationManager/IAllocationManager.hpp b/src/Passes/Source/AllocationManager/IAllocationManager.hpp new file mode 100644 index 0000000000..a60fd0936a --- /dev/null +++ b/src/Passes/Source/AllocationManager/IAllocationManager.hpp @@ -0,0 +1,71 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "QatTypes/QatTypes.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + /// Interface class for allocation management. This interface provides means to allocate and release + /// statically allocated resources such as qubits and results. In a future version, it may be + /// extended with get and store in order to support Arrays and Tuples. + class IAllocationManager + { + public: + using Address = uint64_t; ///< Value type for address + using Index = uint64_t; ///< Index type used to access an array element. + using AllocationManagerPtr = std::shared_ptr; ///< Pointer interface. + + // Construction, moves and copies + // + IAllocationManager(IAllocationManager const&) = delete; + IAllocationManager(IAllocationManager&&) = delete; + IAllocationManager& operator=(IAllocationManager const&) = delete; + IAllocationManager& operator=(IAllocationManager&&) = delete; + + virtual ~IAllocationManager(); + + // Interface + // + + /// Abstract member function to allocate an element or sequence of elements. The developer + /// should not assume continuity of the address segment as this is not guaranteed. Note this + /// function may throw if allocation is not possible. + virtual Address allocate(String const& name = "", Index const& count = 1) = 0; + + /// Abstract member function to release a previously allocated function. Note this function may + /// throw if an invalid address is passed. + virtual void release(Address const& address) = 0; + + /// Abstract member function to reset the allocation manager. This function clears all allocations + /// and resets all statistics. + virtual void reset() = 0; + + // Statistics + // + + /// Current number of registers in use. This function is used to inquire about the current number + /// registers/resources in use. + uint64_t allocationsInUse() const; + + /// Maximum number of registers in use at any one time. The maximum number of registers used at + /// any one time. As an example of usage, this function is useful to calculate the total number of + /// qubits required to execute the entry function. + uint64_t maxAllocationsUsed() const; + + protected: + IAllocationManager() = default; + void updateRegistersInUse(uint64_t n); + + private: + uint64_t registers_in_use_{0}; ///< Used to track the number of registers in use + uint64_t max_registers_used_{0}; ///< Used to track the max number of registers used + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp b/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp new file mode 100644 index 0000000000..dae295c496 --- /dev/null +++ b/src/Passes/Source/AllocationManager/Tests/Unit/main.cpp @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/AllocationManager.hpp" +#include "gtest/gtest.h" + +TEST(AllocationManagerTestSuite, LinearAllocationTestReuse) +{ + auto manager = microsoft::quantum::BasicAllocationManager::createNew(); + manager->setReuseRegisters(true); + + // Expecting ids to be allocated linearly for single + // allocations + auto q1 = manager->allocate(); + EXPECT_EQ(q1, 0); + auto q2 = manager->allocate(); + EXPECT_EQ(q2, 1); + auto q3 = manager->allocate(); + EXPECT_EQ(q3, 2); + auto q4 = manager->allocate(); + EXPECT_EQ(q4, 3); + auto q5 = manager->allocate(); + EXPECT_EQ(q5, 4); + + // We expect that allocating + auto arr1 = manager->allocate("test", 10); + EXPECT_EQ(arr1, 5); + auto arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 15); + + // Testing reusing + manager->release(arr2); + arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 15); + + manager->release(arr2); + manager->release(q1); + manager->release(q2); + manager->release(q3); + manager->release(q4); + manager->release(q5); + arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 15); + + manager->release(arr1); + manager->release(arr2); + arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 0); +} + +TEST(AllocationManagerTestSuite, LinearAllocationTestNoReuse) +{ + auto manager = microsoft::quantum::BasicAllocationManager::createNew(); + manager->setReuseRegisters(false); + + auto q1 = manager->allocate(); + EXPECT_EQ(q1, 0); + auto q2 = manager->allocate(); + EXPECT_EQ(q2, 1); + auto q3 = manager->allocate(); + EXPECT_EQ(q3, 2); + auto q4 = manager->allocate(); + EXPECT_EQ(q4, 3); + auto q5 = manager->allocate(); + EXPECT_EQ(q5, 4); + + // We expect that allocating + auto arr1 = manager->allocate("test", 10); + EXPECT_EQ(arr1, 5); + auto arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 15); + + // Testing reusing + manager->release(arr2); + arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 25); + + manager->release(arr2); + manager->release(q1); + manager->release(q2); + manager->release(q3); + manager->release(q4); + manager->release(q5); + arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 35); + + manager->release(arr1); + manager->release(arr2); + arr2 = manager->allocate("test2", 10); + EXPECT_EQ(arr2, 45); +} + +TEST(AllocationManagerTestSuite, InvalidRelease) +{ + auto manager = microsoft::quantum::BasicAllocationManager::createNew(); + auto q1 = manager->allocate(); + EXPECT_EQ(q1, 0); + auto q2 = manager->allocate(); + EXPECT_EQ(q2, 1); + + EXPECT_THROW(manager->release(28837), std::runtime_error); +} diff --git a/src/Passes/Source/Apps/CMakeLists.txt b/src/Passes/Source/Apps/CMakeLists.txt new file mode 100644 index 0000000000..ea2f2338c9 --- /dev/null +++ b/src/Passes/Source/Apps/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(qat Qat/Qat.cpp Qat/QatConfig.cpp) + +target_link_libraries(qat ${llvm_libs}) +target_link_libraries(qat Logging TransformationRulesPass Rules AllocationManager Commandline Generators Profile Validator ValidationPass ) diff --git a/src/Passes/Source/Apps/Qat/Qat.cpp b/src/Passes/Source/Apps/Qat/Qat.cpp new file mode 100644 index 0000000000..71de0910e1 --- /dev/null +++ b/src/Passes/Source/Apps/Qat/Qat.cpp @@ -0,0 +1,348 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/// QIR Adaptor Tool (QAT) +/// +/// QAT is a tool that helps the enduser to easily build and use new profiles. The tool provides a +/// commandline interface which is configurable through YAML files to validate a specific QIR +/// profile and generate a QIR profile compatible IR from a generic IR. +/// +/// The tool itself make use of LLVM passes to perform analysis and transformations of the supplied +/// IR. These transfornations are described through high-level tasks such as +/// `useStaticQubitArrayAllocation`. +/// +/// To provide an overview of the structure of this tool, we here provide a diagram showing the +/// relation between different instances in the program: +/// +/// +/// ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +/// User input │ │ "Use" relation +/// └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ▼ +/// │ argc, argv +/// ▼ ─ ─▶ "Produce" relation +/// ┌──────────────────────────────┐ +/// │ ParameterParser │◀─┐ Setup arguments +/// └──────────────────────────────┘ │ +/// Load config │ │ +/// ▼ │ +/// ┌──────────────────────────────┐ │ ┌──────────────────────────────────┐ +/// │ ConfigurationManager │──┘ ┌ ─ ─ ─▶│ Ruleset │ +/// └──────────────────────────────┘ └──────────────────────────────────┘ +/// Provide config │ │ │ Rules for +/// ▼ ▼ transformation +/// ┌───────────────────────────────┐─ ─ ─ ┘ ┌──────────────────────────────────┐ +/// │ ProfileGenerator │─ ─ ─ ─ ─ ─ ─▶│ TransformationRulesPass │ +/// └───────────────────────────────┘ └──────────────────────────────────┘ +/// │ LLVM module +/// ▼ pass +/// ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┌──────────────────────────────────┐ +/// Output │◀─ ─ ─ ─ ─ ─ ─ ┤ QAT / LLVM Module Pass Manager │ +/// └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ stdout └──────────────────────────────────┘ +/// +/// + +#include "Apps/Qat/QatConfig.hpp" +#include "Commandline/ConfigurationManager.hpp" +#include "Commandline/ParameterParser.hpp" +#include "Generators/DefaultProfileGenerator.hpp" +#include "Generators/LlvmPassesConfiguration.hpp" +#include "ModuleLoader/ModuleLoader.hpp" +#include "Profile/Profile.hpp" +#include "Rules/Factory.hpp" +#include "Rules/FactoryConfig.hpp" +#include "TransformationRulesPass/TransformationRulesPass.hpp" +#include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" +#include "ValidationPass/ValidationPassConfiguration.hpp" +#include "Validator/Validator.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +#include +#include +#include + +using namespace llvm; +using namespace microsoft::quantum; +void init(); +void init() +{ + // Initialize LLVM passes + PassRegistry& registry = *PassRegistry::getPassRegistry(); + + initializeCore(registry); + + initializeCoroutines(registry); + initializeScalarOpts(registry); + initializeObjCARCOpts(registry); + initializeVectorization(registry); + initializeIPO(registry); + initializeAnalysis(registry); + initializeTransformUtils(registry); + initializeInstCombine(registry); + initializeAggressiveInstCombine(registry); + initializeInstrumentation(registry); + initializeTarget(registry); + + initializeExpandMemCmpPassPass(registry); + initializeScalarizeMaskedMemIntrinPass(registry); + initializeCodeGenPreparePass(registry); + initializeAtomicExpandPass(registry); + initializeRewriteSymbolsLegacyPassPass(registry); + initializeWinEHPreparePass(registry); + initializeDwarfEHPreparePass(registry); + initializeSafeStackLegacyPassPass(registry); + initializeSjLjEHPreparePass(registry); + initializePreISelIntrinsicLoweringLegacyPassPass(registry); + initializeGlobalMergePass(registry); + initializeIndirectBrExpandPassPass(registry); + initializeInterleavedLoadCombinePass(registry); + initializeInterleavedAccessPass(registry); + initializeEntryExitInstrumenterPass(registry); + initializePostInlineEntryExitInstrumenterPass(registry); + initializeUnreachableBlockElimLegacyPassPass(registry); + initializeExpandReductionsPass(registry); + initializeWasmEHPreparePass(registry); + initializeWriteBitcodePassPass(registry); + initializeHardwareLoopsPass(registry); + initializeTypePromotionPass(registry); +} + +int main(int argc, char** argv) +{ + + try + { + // Default generator. A future version of QAT may allow the generator to be selected + // through the command line, but it is hard coded for now. + auto generator = std::make_shared(); + + // Configuration and command line parsing + // + + ConfigurationManager& configuration_manager = generator->configurationManager(); + configuration_manager.addConfig(); + configuration_manager.addConfig(); + + ParameterParser parser; + configuration_manager.setupArguments(parser); + parser.parseArgs(argc, argv); + configuration_manager.configure(parser); + + // Getting the main configuration + auto config = configuration_manager.get(); + + // Setting profile validation configuration + configuration_manager.addConfig( + "validation-configuration", ValidationPassConfiguration::fromProfileName(config.profile())); + + // Loading components + // + generator->registerProfileComponent( + "transformation-rules", + [](TransformationRulesPassConfiguration const& cfg, ProfileGenerator* ptr, Profile& profile) { + auto& ret = ptr->modulePassManager(); + + // Default optimisation pipeline + if (cfg.shouldSimplifyPriorTransform()) + { + auto& pass_builder = ptr->passBuilder(); + llvm::ModulePassManager pipeline = + pass_builder.buildPerModuleDefaultPipeline(ptr->optimisationLevel()); + ret.addPass(std::move(pipeline)); + } + + // Defining the mapping + RuleSet rule_set; + auto factory = + RuleFactory(rule_set, profile.getQubitAllocationManager(), profile.getResultAllocationManager()); + factory.usingConfiguration(ptr->configurationManager().get()); + + // Creating profile pass + ret.addPass(TransformationRulesPass(std::move(rule_set), cfg, &profile)); + }); + + if (!config.load().empty()) + { + // TODO (tfr): Add support for multiple loads + void* handle = dlopen(config.load().c_str(), RTLD_LAZY); + + if (handle == nullptr) + { + std::cerr << "Invalid component " << config.load() << std::endl; + } + else + { + using LoadFunctionPtr = void (*)(ProfileGenerator*); + LoadFunctionPtr load_component; + load_component = reinterpret_cast(dlsym(handle, "loadComponent")); + + load_component(generator.get()); + } + } + + generator->registerProfileComponent( + "llvm-passes", [](LlvmPassesConfiguration const& cfg, ProfileGenerator* ptr, Profile&) { + auto pass_pipeline = cfg.passPipeline(); + if (!pass_pipeline.empty()) + { + + auto& pass_builder = ptr->passBuilder(); + auto& npm = ptr->modulePassManager(); + + if (auto err = pass_builder.parsePassPipeline(npm, pass_pipeline, false, false)) + { + throw std::runtime_error( + "Failed to set pass pipeline up. Value: '" + pass_pipeline + + "', error: " + toString(std::move(err))); + } + } + else if (cfg.alwaysInline()) + { + auto& ret = ptr->modulePassManager(); + auto& pass_builder = ptr->passBuilder(); + ret.addPass(llvm::AlwaysInlinerPass()); + + auto inliner_pass = pass_builder.buildInlinerPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None, ptr->isDebugMode()); + ret.addPass(std::move(inliner_pass)); + } + else if (!cfg.disableDefaultPipeline()) + { + auto& mpm = ptr->modulePassManager(); + + llvm::PassBuilder::OptimizationLevel opt = llvm::PassBuilder::OptimizationLevel::O3; + + // If not explicitly disabled, we fall back to the default LLVM pipeline + auto& pass_builder = ptr->passBuilder(); + llvm::ModulePassManager pipeline1 = pass_builder.buildPerModuleDefaultPipeline(opt); + mpm.addPass(std::move(pipeline1)); + + llvm::ModulePassManager pipeline2 = + pass_builder.buildModuleSimplificationPipeline(opt, llvm::PassBuilder::ThinLTOPhase::None); + mpm.addPass(std::move(pipeline2)); + + llvm::ModulePassManager pipeline3 = + pass_builder.buildModuleOptimizationPipeline(opt, ptr->isDebugMode()); + mpm.addPass(std::move(pipeline3)); + } + }); + + // Reconfiguring to get all the arguments of the passes registered + parser.reset(); + + configuration_manager.setupArguments(parser); + parser.parseArgs(argc, argv); + configuration_manager.configure(parser); + + // In case we debug, we also print the settings to allow provide a full + // picture of what is going. This step deliberately comes before validating + // the input to allow dumping the configuration if something goes wrong. + if (config.shouldDumpConfig()) + { + configuration_manager.printConfiguration(); + } + + // Checking that we have sufficient information to proceed. If not we print + // usage instructions and the corresponding description of how to use the tool. + if (parser.arguments().empty()) + { + std::cerr << "Usage: " << argv[0] << " [options] filename" << std::endl; + configuration_manager.printHelp(); + std::cerr << "\n"; + exit(-1); + } + + // Loading IR from file(s). + // + + LLVMContext context; + init(); + + auto module = std::make_unique("qat-link", context); + ModuleLoader loader(module.get()); + + for (auto const& arg : parser.arguments()) + { + if (!loader.addIrFile(arg)) + { + llvm::errs() << "Could not load " << arg << "\n"; + return -1; + } + } + + if (!module) + { + std::cerr << "Invalid IR." << std::endl; + exit(-1); + } + + // Getting the optimisation level + // + auto optimisation_level = llvm::PassBuilder::OptimizationLevel::O0; + + // Setting the optimisation level + if (config.isOpt1Enabled()) + { + optimisation_level = llvm::PassBuilder::OptimizationLevel::O1; + } + + if (config.isOpt2Enabled()) + { + optimisation_level = llvm::PassBuilder::OptimizationLevel::O2; + } + + if (config.isOpt3Enabled()) + { + optimisation_level = llvm::PassBuilder::OptimizationLevel::O3; + } + + // Profile manipulation + // + + // Creating the profile that will be used for generation and validation + auto profile = generator->newProfile(config.profile(), optimisation_level, config.isDebugMode()); + + if (config.shouldGenerate()) + { + profile.apply(*module); + } + + // We deliberately emit LLVM prior to verification and validation + // to allow output the IR for debugging purposes. + if (config.shouldEmitLlvm()) + { + llvm::outs() << *module << "\n"; + } + else + { + llvm::WriteBitcodeToFile(*module, llvm::outs()); + } + + if (config.verifyModule()) + { + if (!profile.verify(*module)) + { + std::cerr << "IR is broken." << std::endl; + exit(-1); + } + } + + if (config.shouldValidate()) + { + if (!profile.validate(*module)) + { + std::cerr << "IR did not validate to the profile constraints." << std::endl; + exit(-1); + } + } + } + catch (std::exception const& e) + { + std::cerr << "An error occurred: " << e.what() << std::endl; + exit(-1); + } + + return 0; +} diff --git a/src/Passes/Source/Apps/Qat/QatConfig.cpp b/src/Passes/Source/Apps/Qat/QatConfig.cpp new file mode 100644 index 0000000000..09e9233f29 --- /dev/null +++ b/src/Passes/Source/Apps/Qat/QatConfig.cpp @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Apps/Qat/QatConfig.hpp" +#include "Commandline/ConfigurationManager.hpp" + +namespace microsoft +{ +namespace quantum +{ + + void QatConfig::setup(ConfigurationManager& config) + { + + config.setSectionName( + "Base configuration", "Configuration of the quantum adoption tool to execute a specific behaviour."); + config.addParameter(load_, "load", "Load component."); + config.addParameter( + generate_, "apply", "Applies a profile to transform the IR in correspondence with the profile."); + config.addParameter(validate_, "validate", "Executes the validation procedure."); + config.addParameter(profile_, "profile", "Sets the profile."); + config.addParameter(emit_llvm_, "S", "Emits LLVM IR to the standard output."); + config.addParameter(opt0_, "O0", "Optimisation level 0."); + config.addParameter(opt1_, "O1", "Optimisation level 1."); + config.addParameter(opt2_, "O2", "Optimisation level 2."); + config.addParameter(opt3_, "O3", "Optimisation level 3."); + + config.addParameter(verify_module_, "verify-module", "Verifies the module after transformation."); + + config.addParameter(dump_config_, "dump-config", "Prints the configuration to the standard output."); + } + + bool QatConfig::shouldGenerate() const + { + return generate_; + } + + bool QatConfig::shouldValidate() const + { + return validate_; + } + + String QatConfig::profile() const + { + return profile_; + } + + bool QatConfig::shouldEmitLlvm() const + { + return emit_llvm_; + } + + bool QatConfig::isOpt0Enabled() const + { + return opt0_; + } + + bool QatConfig::isOpt1Enabled() const + { + return opt1_; + } + + bool QatConfig::isOpt2Enabled() const + { + return opt2_; + } + + bool QatConfig::isOpt3Enabled() const + { + return opt3_; + } + + bool QatConfig::verifyModule() const + { + return verify_module_; + } + + bool QatConfig::isDebugMode() const + { + return debug_; + } + + bool QatConfig::shouldDumpConfig() const + { + return dump_config_; + } + + String QatConfig::load() const + { + return load_; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Apps/Qat/QatConfig.hpp b/src/Passes/Source/Apps/Qat/QatConfig.hpp new file mode 100644 index 0000000000..90b7d3aabd --- /dev/null +++ b/src/Passes/Source/Apps/Qat/QatConfig.hpp @@ -0,0 +1,81 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "QatTypes/QatTypes.hpp" + +namespace microsoft +{ +namespace quantum +{ + + /// Main configuration class for the qat command-line program. + class QatConfig + { + public: + // Functions required by configuration manager + // + + /// Setup function that binds instance variables to the command-line/configuration entries. + /// This function also provide descriptions of each of the properties below. + void setup(ConfigurationManager& config); + + // Flags and options + // + + /// List of dynamic libraries to load. + String load() const; + + /// Flag that indicates whether or not we are generating a new QIR by applying a profile. + bool shouldGenerate() const; + + /// Flag to indicate whether or not to verify that the (Q)IR is a valid LLVM IR. + bool verifyModule() const; + + /// Flag to indicate whether or not to validate the compliance with the QIR profile. + bool shouldValidate() const; + + /// String to request a specific profile name. Default is base. + String profile() const; + + /// Indicates whether or not the QIR adaptor tool should emit LLVM IR to the standard output. + bool shouldEmitLlvm() const; + + /// Tells if the optimisation level 0 is enabled. Note higher OX override lower ones. + bool isOpt0Enabled() const; + + /// Tells if the optimisation level 1 is enabled. Note higher OX override lower ones. + bool isOpt1Enabled() const; + + /// Tells if the optimisation level 2 is enabled. Note higher OX override lower ones. + bool isOpt2Enabled() const; + + /// Tells if the optimisation level 3 is enabled. Note higher OX override lower ones. + bool isOpt3Enabled() const; + + /// Enables debug output. + bool isDebugMode() const; + + /// Request the full configuration to be dumped to the screen. + bool shouldDumpConfig() const; + + private: + // Variables to be bound to the configuration manager + // + String load_{""}; + bool generate_{false}; + bool validate_{false}; + String profile_{"generic"}; + bool emit_llvm_{false}; + bool opt0_{false}; + bool opt1_{false}; + bool opt2_{false}; + bool opt3_{false}; + bool verify_module_{false}; + + bool debug_{false}; + bool dump_config_{false}; + }; +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/CMakeLists.txt b/src/Passes/Source/CMakeLists.txt new file mode 100644 index 0000000000..0dbabc01f0 --- /dev/null +++ b/src/Passes/Source/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.4.3) + +microsoft_add_library(Logging) + +microsoft_add_library(TestTools) +microsoft_add_library_tests(TestTools Generators Logging) + +microsoft_add_library(Commandline) +microsoft_add_library_tests(Commandline Logging) + +microsoft_add_library(Profile) +microsoft_add_library_tests(Profile) + +microsoft_add_library(Validator) +target_link_libraries(Validator PRIVATE Logging) + +microsoft_add_library_tests(Validator ValidationPass Logging) +microsoft_add_library(ValidationPass Logging) + +microsoft_add_library(AllocationManager) +microsoft_add_library_tests(AllocationManager Logging) + +microsoft_add_library(TransformationRulesPass) +target_link_libraries(TransformationRulesPass PRIVATE Rules Commandline AllocationManager) +microsoft_add_library_tests(TransformationRulesPass Rules TransformationRulesPass AllocationManager Commandline Generators Validator ValidationPass Logging) + + +microsoft_add_library(Rules) +microsoft_add_library_tests(Rules Rules TransformationRulesPass AllocationManager Commandline Generators Logging) + +target_link_libraries(Rules PRIVATE AllocationManager) + +microsoft_add_library(Generators) +target_link_libraries(Generators PRIVATE Rules Commandline AllocationManager TransformationRulesPass Profile Validator ValidationPass) +microsoft_add_library_tests(Generators Rules TransformationRulesPass AllocationManager Commandline Generators Logging) + +add_subdirectory(Apps) diff --git a/src/Passes/Source/Commandline/ConfigBind.hpp b/src/Passes/Source/Commandline/ConfigBind.hpp new file mode 100644 index 0000000000..da68876ad3 --- /dev/null +++ b/src/Passes/Source/Commandline/ConfigBind.hpp @@ -0,0 +1,205 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/IConfigBind.hpp" +#include "Commandline/ParameterParser.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Generic implementation of the bind interface for different types. This class holds the name of + /// the command line parameter and a reference variable corresponding to it. It implements + /// serialisers and deserialisers to allow transforming strings to native values and vice versa. + template class ConfigBind : public IConfigBind + { + public: + using Type = T; + + /// Helper template to conditionally disable implementation unless a specific type is used. + template + using EnableIf = typename std::enable_if::value, R>::type; + + // Constructors, operators and destructor + // + + ConfigBind() = delete; + ConfigBind(ConfigBind const&) = delete; + ConfigBind(ConfigBind&&) = delete; + ConfigBind& operator=(ConfigBind const&) = delete; + ConfigBind& operator=(ConfigBind&&) = delete; + ~ConfigBind() override = default; + + /// Constructor to bind value to parameter. This class holds a reference to a variable together + /// with the name it is expected to have when passed through the parameter parser. + ConfigBind(Type& bind, T default_value, String const& name, String const& description); + + // Interface implementation + // + + /// Adds the argument to the parser. + bool setupArguments(ParameterParser& parser) override; + + /// Configures the bound value. This method examines the parsed input + /// and use updates the bound value accordingly. + bool configure(ParameterParser const& parser) override; + + /// String representation of the bound value. + String value() override; + + private: + /// Generic function to setup arguments of any type. + template bool setupArguments(ParameterParser&, R const&); + + /// Specialised function setting arguments up for booleans. + bool setupArguments(ParameterParser& parser, bool const&); + + /// Generic function that changes the parameter name based on the value type and default value. + template void alterNameBasedOnType(R const& default_value); + + /// Specialised function that changes the parameter name based on default value for booleans. + void alterNameBasedOnType(bool const& default_value); + + /// Generic string serialization. + template String valueAsString(A const&); + + /// Specialised serialization for booleans. + template String valueAsString(EnableIf const&); + + /// Generic deserialization of string values from parser. + template void loadValue(ParameterParser const& parser, R const& default_value); + + /// Specialised deserialization of string values from parser for booleans. + template void loadValue(ParameterParser const& parser, EnableIf const& default_value); + + /// Specialised deserialization of string values from parser for strings. + template + void loadValue(ParameterParser const& parser, EnableIf const& default_value); + + Type& bind_; ///< Bound variable to be updated. + Type default_value_; ///< Default value. + }; + + template + ConfigBind::ConfigBind(Type& bind, T default_value, String const& name, String const& description) + : IConfigBind(name, description) + , bind_{bind} + , default_value_{std::move(default_value)} + { + alterNameBasedOnType(default_value_); + } + + template template void ConfigBind::alterNameBasedOnType(R const& default_value) + { + std::stringstream ss{""}; + ss << default_value; + setDefault(static_cast(ss.str())); + } + + template void ConfigBind::alterNameBasedOnType(bool const& default_value) + { + markAsFlag(); + + if (default_value) + { + setDefault("true"); + } + else + { + setDefault("false"); + } + } + + template bool ConfigBind::setupArguments(ParameterParser& parser) + { + return setupArguments(parser, default_value_); + } + + template template bool ConfigBind::setupArguments(ParameterParser&, R const&) + { + return true; + } + + template bool ConfigBind::setupArguments(ParameterParser& parser, bool const&) + { + parser.addFlag(name()); + return true; + } + + template bool ConfigBind::configure(ParameterParser const& parser) + { + loadValue(parser, default_value_); + return true; + } + + template String ConfigBind::value() + { + return valueAsString(default_value_); + } + + template template String ConfigBind::valueAsString(A const&) + { + std::stringstream ss{""}; + ss << bind_; + return static_cast(ss.str()); + } + + template template String ConfigBind::valueAsString(EnableIf const&) + { + std::stringstream ss{""}; + ss << (bind_ ? "true" : "false"); + return static_cast(ss.str()); + } + + template + template + void ConfigBind::loadValue(ParameterParser const& parser, R const& default_value) + { + bind_ = default_value; + + if (parser.has(name())) + { + std::stringstream ss{parser.get(name())}; + ss >> bind_; + } + } + + template + template + void ConfigBind::loadValue(ParameterParser const& parser, EnableIf const& default_value) + { + bind_ = default_value; + if (parser.has(name())) + { + bind_ = true; + } + else if (parser.has("no-" + name())) + { + bind_ = false; + } + } + + template + template + void ConfigBind::loadValue(ParameterParser const& parser, EnableIf const& default_value) + { + bind_ = default_value; + + if (parser.has(name())) + { + bind_ = parser.get(name()); + } + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ConfigurationManager.cpp b/src/Passes/Source/Commandline/ConfigurationManager.cpp new file mode 100644 index 0000000000..ba2611dfbd --- /dev/null +++ b/src/Passes/Source/Commandline/ConfigurationManager.cpp @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" + +using namespace microsoft::quantum; + +namespace microsoft +{ +namespace quantum +{ + + void ConfigurationManager::setupArguments(ParameterParser& parser) + { + for (auto& section : config_sections_) + { + parser.addFlag("disable-" + section.id); + } + + for (auto& section : config_sections_) + { + for (auto& c : section.settings) + { + if (!c->setupArguments(parser)) + { + throw std::runtime_error("Failed to set parser arguments up."); + } + } + } + } + + void ConfigurationManager::configure(ParameterParser const& parser) + { + + for (auto& section : config_sections_) + { + *section.active = (parser.get("disable-" + section.id, "false") != "true"); + } + + for (auto& section : config_sections_) + { + for (auto& c : section.settings) + { + if (!c->configure(parser)) + { + throw std::runtime_error("Failed configure the section."); + } + } + } + } + + void ConfigurationManager::printHelp() const + { + std::cout << std::setfill(' '); + + // Enable or disable components + std::cout << std::endl; + std::cout << "Component configuration" + << " - "; + std::cout << "Used to disable or enable components" << std::endl; + std::cout << std::endl; + for (auto& section : config_sections_) + { + if (!section.id.empty()) + { + std::cout << std::setw(50) << std::left << ("--disable-" + section.id) << "Disables " << section.name + << ". "; + std::cout << "Default: true" << std::endl; + } + } + + // Component configuration + for (auto& section : config_sections_) + { + std::cout << std::endl; + std::cout << section.name << " - "; + std::cout << section.description << std::endl; + std::cout << std::endl; + + for (auto& c : section.settings) + { + if (c->isFlag()) + { + if (c->defaultValue() == "false") + { + std::cout << std::setw(50) << std::left << ("--" + c->name()) << c->description() << " "; + } + else + { + std::cout << std::setw(50) << std::left << ("--[no-]" + c->name()) << c->description() << " "; + } + } + else + { + std::cout << std::setw(50) << std::left << ("--" + c->name()) << c->description() << " "; + } + std::cout << "Default: " << c->defaultValue() << std::endl; + } + } + } + + void ConfigurationManager::printConfiguration() const + { + std::cout << std::setfill('.'); + + std::cout << "; # " + << "Components" + << "\n"; + for (auto& section : config_sections_) + { + if (!section.id.empty()) + { + std::cout << "; " << std::setw(50) << std::left << ("disable-" + section.id) << ": " + << (*section.active ? "false" : "true") << "\n"; + } + } + std::cout << "; \n"; + + for (auto& section : config_sections_) + { + std::cout << "; # " << section.name << "\n"; + for (auto& c : section.settings) + { + std::cout << "; " << std::setw(50) << std::left << c->name() << ": " << c->value() << "\n"; + } + std::cout << "; \n"; + } + } + + void ConfigurationManager::setSectionName(String const& name, String const& description) + { + config_sections_.back().name = name; + config_sections_.back().description = description; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ConfigurationManager.hpp b/src/Passes/Source/Commandline/ConfigurationManager.hpp new file mode 100644 index 0000000000..f228cfd2a1 --- /dev/null +++ b/src/Passes/Source/Commandline/ConfigurationManager.hpp @@ -0,0 +1,208 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigBind.hpp" +#include "Commandline/IConfigBind.hpp" +#include "Commandline/ParameterParser.hpp" +#include "QatTypes/QatTypes.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// ConfigurationManager is a class that holds a collection of configurations (sections). Each of + /// these sections are embodied in their own class with a one-to-one mapping between configuration + /// section and the configuration type. As an example, if one wishes to make a configuration for the + /// class Foo, one would create a class FooConfig which would hold all the variables that are + /// configurable and then add FooConfig to the ConfigurationManager using `addConfig()`. For + /// FooConfig to fulfill the concept of a configuration, it must implement a setup functions whose + /// first argument is the ConfigurationManager. + class ConfigurationManager + { + public: + using IConfigBindPtr = std::shared_ptr; ///< Pointer class used to bind a parameter to a value. + using ConfigList = std::vector; ///< List of bound variables. + using VoidPtr = std::shared_ptr; ///< Type-erased configuration pointer. + using TypeId = std::type_index; ///< Type index class. + using BoolPtr = std::shared_ptr; + + /// Section defines a section in the configuration. It holds the type of the configuration class, + /// the name of the section a description, the instance of the configuration class itself and list + /// of parameter bindings. + struct Section + { + TypeId type{TypeId(typeid(std::nullptr_t))}; ///< Type of the configuration. + String name{}; ///< Name of the section. + String description{}; ///< Description of the section. + VoidPtr configuration{}; ///< Configuration class instance. + ConfigList settings{}; ///< List of parameter bindings. + BoolPtr active{nullptr}; ///< Whether or not this component is active; + String id{}; ///< Id referring to this component. + }; + using Sections = std::vector
; ///< List of available sections + + // Constructors, copy and move operators, destructor + // + + /// Configuration manager is default constructible, non-copyable and non-movable. + ConfigurationManager() = default; + ConfigurationManager(ConfigurationManager const&) = delete; + ConfigurationManager(ConfigurationManager&&) = delete; + ConfigurationManager& operator=(ConfigurationManager const&) = delete; + ConfigurationManager& operator=(ConfigurationManager&&) = delete; + + // Configuration setup + // + + /// Adds all bound variables as parser arguments. + void setupArguments(ParameterParser& parser); + + /// Configures the value of each bound variable given a parser instance. + void configure(ParameterParser const& parser); + + // Managing configuration + // + + /// Given an instance of the ConfigurationManager, this method override settings of class T. + template inline void setConfig(T const& value); + + /// Gets the configuration instance of type T. + template inline T const& get() const; + + // Support functions + // + + /// Prints options for configurability to the terminal. + void printHelp() const; + + /// Prints the configuration to the terminal. The configuration print is LLVM IR compatible + /// meaning that every line starts with a semicolon ; to ensure that it is interpreted as a + /// comment. + void printConfiguration() const; + + // Configuration functions + // + + /// Adds a new configuration of type T. + template inline void addConfig(String const& id = "", T const& default_value = T()); + + /// Whether or not the component associated with T is active. + template inline bool isActive(); + + /// Sets the section name. This method is used by the configuration class to set a section + /// name. + void setSectionName(String const& name, String const& description); + + /// Adds a new parameter with a default value to the configuration section. This function should + /// be used by the configuration class. + template + inline void addParameter(T& bind, T default_value, String const& name, String const& description); + + /// Adds a new parameter to the configuration section. This method uses the bound variable value + /// as default value. This function should be used by the configuration class. + template inline void addParameter(T& bind, String const& name, String const& description); + + private: + /// Helper function to get a reference to the configuration of type T. + template inline T& getInternal() const; + + Sections config_sections_{}; ///< All available sections within the ConfigurationManager instance + }; + + template inline void ConfigurationManager::addConfig(String const& id, T const& default_value) + { + Section new_section{std::type_index(typeid(T))}; + + auto ptr = std::make_shared(default_value); + new_section.configuration = ptr; + new_section.active = std::make_shared(true); + new_section.id = id; + + config_sections_.emplace_back(std::move(new_section)); + ptr->setup(*this); + } + + template inline T& ConfigurationManager::getInternal() const + { + VoidPtr ptr{nullptr}; + auto type = std::type_index(typeid(T)); + + for (auto& section : config_sections_) + { + if (section.type == type) + { + ptr = section.configuration; + break; + } + } + + if (ptr == nullptr) + { + throw std::runtime_error("Could not find configuration class."); + } + + return *static_cast(ptr.get()); + } + + template inline void ConfigurationManager::setConfig(T const& value) + { + auto& config = getInternal(); + config = value; + } + + template inline T const& ConfigurationManager::get() const + { + return getInternal(); + } + + template inline bool ConfigurationManager::isActive() + { + BoolPtr ptr{nullptr}; + auto type = std::type_index(typeid(T)); + + for (auto& section : config_sections_) + { + if (section.type == type) + { + ptr = section.active; + break; + } + } + + if (ptr == nullptr) + { + throw std::runtime_error("Could not find configuration class."); + } + + return *ptr; + } + + template + inline void ConfigurationManager::addParameter( + T& bind, + T default_value, + String const& name, + String const& description) + { + auto ptr = std::make_shared>(bind, default_value, name, description); + config_sections_.back().settings.push_back(ptr); + } + + template + inline void ConfigurationManager::addParameter(T& bind, String const& name, String const& description) + { + auto ptr = std::make_shared>(bind, T(bind), name, description); + config_sections_.back().settings.push_back(ptr); + } +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/IConfigBind.cpp b/src/Passes/Source/Commandline/IConfigBind.cpp new file mode 100644 index 0000000000..6659e39989 --- /dev/null +++ b/src/Passes/Source/Commandline/IConfigBind.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Commandline/IConfigBind.hpp" + +using namespace microsoft::quantum; + +namespace microsoft +{ +namespace quantum +{ + + IConfigBind::IConfigBind(String const& name, String const& description) + : name_{name} + , description_{description} + { + } + + IConfigBind::~IConfigBind() = default; + + String IConfigBind::name() const + { + return name_; + } + + String IConfigBind::description() const + { + return description_; + } + + void IConfigBind::setName(String const& name) + { + name_ = name; + } + + bool IConfigBind::isFlag() const + { + return is_flag_; + } + + String IConfigBind::defaultValue() const + { + return str_default_value_; + } + + void IConfigBind::markAsFlag() + { + is_flag_ = true; + } + + void IConfigBind::setDefault(String const& v) + { + str_default_value_ = v; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/IConfigBind.hpp b/src/Passes/Source/Commandline/IConfigBind.hpp new file mode 100644 index 0000000000..2153eac7d6 --- /dev/null +++ b/src/Passes/Source/Commandline/IConfigBind.hpp @@ -0,0 +1,100 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ParameterParser.hpp" +#include "QatTypes/QatTypes.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Interface class to bind a variable to a configuration flag. This class provides + /// the necessary interface to bind variables and populate their value based on given command-line + /// arguments. + class IConfigBind + { + public: + // Deleted constructors and deleted operators + // + // Strictly speaking the code would remain correct if we allowed copy and/or move, but + // we have chosen to ban them by choice as potential bugs arising from allowing copy and/or + // move can be difficult to find. We consider this behaviour a part of the interface definition. + IConfigBind(IConfigBind const&) = delete; + IConfigBind(IConfigBind&&) = delete; + IConfigBind& operator=(IConfigBind const&) = delete; + IConfigBind& operator=(IConfigBind&&) = delete; + + // Virtual destructor + // + virtual ~IConfigBind(); + + // Interface + // + + /// Interface function to register configuration in the parser. This function + /// register the configuration to the parameter parser. This makes the configuration + /// available in the parameter parsers help function. This method should return true if arguments + /// were successfully setup. + virtual bool setupArguments(ParameterParser& parser) = 0; + + /// Interface function to extract configuration from the command line arguments. Given an instance + /// of the command line parameter parser, this function is meant to read the command line + /// arguments, interpret it and set the bound variable value (if present). This method should + /// return true if configure operation was successful. + virtual bool configure(ParameterParser const& parser) = 0; + + /// Interface function to return a string representation of the current value of the + /// bound variable. + virtual String value() = 0; + + // Properties + // + + /// Returns the name of the bound configuration variable. + String name() const; + + /// Returns the description of the configuration variable. + String description() const; + + /// Indicates whether or not this + bool isFlag() const; + + /// Returns the default value for the flag. + String defaultValue() const; + + protected: + // Constructor + // + IConfigBind(String const& name, String const& description); + + // Configuration + // + + /// Sets the name of the configuration variable. + void setName(String const& name); + + /// Marks the variable as a flag. + void markAsFlag(); + + /// Sets the default value as a string. + void setDefault(String const& v); + + private: + String name_; ///< Name that which sets the value. + String description_; ///< Description of the option or flag. + bool is_flag_{false}; ///< Whether or not the variable is a flag. + String str_default_value_; ///< Default value represented as a string. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ParameterParser.cpp b/src/Passes/Source/Commandline/ParameterParser.cpp new file mode 100644 index 0000000000..a370062f70 --- /dev/null +++ b/src/Passes/Source/Commandline/ParameterParser.cpp @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ParameterParser.hpp" + +#include +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + void ParameterParser::parseArgs(int argc, char** argv) + { + uint64_t i = 1; + std::vector values; + while (i < static_cast(argc)) + { + values.push_back(parseSingleArg(argv[i])); + ++i; + } + + i = 0; + while (i < values.size()) + { + auto& v = values[i]; + ++i; + + if (!v.is_key) + { + arguments_.push_back(v.value); + continue; + } + + if (i >= values.size()) + { + settings_[v.value] = "true"; + continue; + } + + auto& v2 = values[i]; + if (!v2.is_key && isOption(v.value)) + { + settings_[v.value] = v2.value; + ++i; + continue; + } + + settings_[v.value] = "true"; + } + } + + void ParameterParser::addFlag(String const& v) + { + flags_.insert(v); + } + + String const& ParameterParser::get(String const& name, String const& default_value) const noexcept + { + auto it = settings_.find(name); + if (it == settings_.end()) + { + return default_value; + } + + return it->second; + } + + String const& ParameterParser::get(String const& name) const + { + auto it = settings_.find(name); + if (it == settings_.end()) + { + throw std::runtime_error("Could not find setting '" + name + "'."); + } + + return it->second; + } + + bool ParameterParser::has(String const& name) const noexcept + { + auto it = settings_.find(name); + return (it != settings_.end()); + } + + ParameterParser::Arguments const& ParameterParser::arguments() const + { + return arguments_; + } + + String const& ParameterParser::getArg(Arguments::size_type const& n) const + { + return arguments_[n]; + } + + ParameterParser::ParsedValue ParameterParser::parseSingleArg(String key) + { + bool is_key = false; + if (key.size() > 2 && key.substr(0, 2) == "--") + { + is_key = true; + key = key.substr(2); + } + else if (key.size() > 1 && key.substr(0, 1) == "-") + { + is_key = true; + key = key.substr(1); + } + return {is_key, key}; + } + + bool ParameterParser::isOption(String const& key) + { + if (flags_.find(key) != flags_.end()) + { + return false; + } + + return true; + } + + void ParameterParser::reset() + { + arguments_.clear(); + settings_.clear(); + flags_.clear(); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/ParameterParser.hpp b/src/Passes/Source/Commandline/ParameterParser.hpp new file mode 100644 index 0000000000..faf0bef17e --- /dev/null +++ b/src/Passes/Source/Commandline/ParameterParser.hpp @@ -0,0 +1,103 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "QatTypes/QatTypes.hpp" + +#include +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Parameter parser class which allows the developer to specify a set of default settings and + /// update those using the commandline argc and argv. + class ParameterParser + { + public: + using Arguments = std::vector; + using Flags = std::unordered_set; + using SettingsMap = std::unordered_map; + + // Construction and deconstrution configuration + // + + ParameterParser() = default; + + // No copy construction. + ParameterParser(ParameterParser const& other) = delete; + + // Allow move semantics. + ParameterParser(ParameterParser&& other) = default; + + // Default destruction. + ~ParameterParser() = default; + + // Configuration + // + + /// Marks a name as a flag (as opposed to an option). + /// This ensures that no parameter is expected after + /// the flag is specified. For instance `--debug` is + /// a flag as opposed to `--log-level 3` which is an + /// option. + void addFlag(String const& v); + + // Operation + // + + /// Parses the command line arguments given the argc and argv + /// from the main function. + void parseArgs(int argc, char** argv); + + /// Returns list of arguments without flags and/or options + /// included. + Arguments const& arguments() const; + + /// Returns the n'th commandline argument. + String const& getArg(Arguments::size_type const& n) const; + + /// Gets a named setting, falling back to a default if the key is not found. + String const& get(String const& name, String const& default_value) const noexcept; + + /// Gets a named setting. This method throws if the setting is not present. + String const& get(String const& name) const; + + /// Checks whether or not a given parameter is present. + bool has(String const& name) const noexcept; + + /// Resets the state of the parser to its construction state + void reset(); + + private: + /// Struct that contains parsed and interpreted values of command line arguments. + struct ParsedValue + { + bool is_key{false}; ///< Whether or not a parsed value should be considered a key + String value; ///< Value after parsing. + }; + + // Helper functions + // + + // Parses a single argument and returns the parsed value. This function + // determines if the string was specified to be a key or a value. + ParsedValue parseSingleArg(String key); + + /// Checks whether a key is an option (or a flag). Returns true if it is + /// and option and false if it is a flags. + bool isOption(String const& key); + + // Storage of parsed data + // + Flags flags_{}; ///< Set of flags + Arguments arguments_{}; ///< List of remaining arguments + SettingsMap settings_; ///< Settings map that keeps all specified settings. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Commandline/Tests/Unit/configuration.cpp b/src/Passes/Source/Commandline/Tests/Unit/configuration.cpp new file mode 100644 index 0000000000..25ebf9dbf7 --- /dev/null +++ b/src/Passes/Source/Commandline/Tests/Unit/configuration.cpp @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/AllocationManager.hpp" +#include "Commandline/ConfigurationManager.hpp" +#include "gtest/gtest.h" + +using namespace microsoft::quantum; + +namespace +{ + +class TestConfig1 +{ + public: + void setup(ConfigurationManager& config) + { + config.setSectionName("Base configuration", ""); + config.addParameter(param1_, "param1", ""); + config.addParameter(param2_, "param2", ""); + config.addParameter(param3_, "param3", ""); + } + + bool param1() const + { + return param1_; + } + + std::string param2() const + { + return param2_; + } + + int32_t param3() const + { + return param3_; + } + + private: + bool param1_{false}; + std::string param2_{""}; + int32_t param3_{9}; +}; + +class TestConfig2 +{ + public: + void setup(ConfigurationManager& config) + { + config.setSectionName("Base configuration", ""); + config.addParameter(param1_, "param1", ""); + config.addParameter(param2_, "param2", ""); + config.addParameter(param3_, "param3", ""); + } + + bool param1() const + { + return param1_; + } + + std::string param2() const + { + return param2_; + } + + int32_t param3() const + { + return param3_; + } + + private: + bool param1_{true}; + std::string param2_{"xxxx"}; + int32_t param3_{9}; +}; + +} // namespace + +TEST(CommandlineTestSuite, Configuration) +{ + { + ConfigurationManager configuration_manager; + configuration_manager.addConfig(); + + ParameterParser parser; + configuration_manager.setupArguments(parser); + char* args[] = {"main", "--param1", "--param2", "hello", "--param3", "1337"}; + parser.parseArgs(6, args); + + configuration_manager.configure(parser); + + auto& config = configuration_manager.get(); + EXPECT_EQ(config.param1(), true); + EXPECT_EQ(config.param2(), "hello"); + EXPECT_EQ(config.param3(), 1337); + } + + { + ConfigurationManager configuration_manager; + configuration_manager.addConfig(); + + ParameterParser parser; + configuration_manager.setupArguments(parser); + char* args[] = {"main", "--no-param1", "--param2", "ms", "--param3", "17372"}; + parser.parseArgs(6, args); + + configuration_manager.configure(parser); + + auto& config = configuration_manager.get(); + EXPECT_EQ(config.param1(), false); + EXPECT_EQ(config.param2(), "ms"); + EXPECT_EQ(config.param3(), 17372); + } + + // Testing default values + { + // Testing default arguments + ConfigurationManager configuration_manager; + configuration_manager.addConfig(); + + ParameterParser parser; + configuration_manager.setupArguments(parser); + char* args[] = {"main"}; + parser.parseArgs(1, args); + + configuration_manager.configure(parser); + + auto& config = configuration_manager.get(); + EXPECT_EQ(config.param1(), true); + EXPECT_EQ(config.param2(), "xxxx"); + EXPECT_EQ(config.param3(), 9); + } + + // Testing opposite boolean default + { + ConfigurationManager configuration_manager; + configuration_manager.addConfig(); + + ParameterParser parser; + configuration_manager.setupArguments(parser); + char* args[] = {"main", "--no-param1", "--param2", "msss", "--param3", "17372"}; + parser.parseArgs(6, args); + + configuration_manager.configure(parser); + + auto& config = configuration_manager.get(); + EXPECT_EQ(config.param1(), false); + EXPECT_EQ(config.param2(), "msss"); + EXPECT_EQ(config.param3(), 17372); + } +} diff --git a/src/Passes/Source/Generators/DefaultProfileGenerator.cpp b/src/Passes/Source/Generators/DefaultProfileGenerator.cpp new file mode 100644 index 0000000000..ae9a409672 --- /dev/null +++ b/src/Passes/Source/Generators/DefaultProfileGenerator.cpp @@ -0,0 +1,172 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "Rules/FactoryConfig.hpp" +#include "Rules/RuleSet.hpp" +#include "TransformationRulesPass/TransformationRulesPass.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + DefaultProfileGenerator::DefaultProfileGenerator() + { + configurationManager().addConfig(); + + registerProfileComponent( + "transformation-rules", + [](TransformationRulesPassConfiguration const& config, ProfileGenerator* ptr, Profile& profile) { + auto& ret = ptr->modulePassManager(); + + // Default optimisation pipeline + if (config.shouldSimplifyPriorTransform()) + { + auto& pass_builder = ptr->passBuilder(); + llvm::ModulePassManager pipeline = + pass_builder.buildPerModuleDefaultPipeline(ptr->optimisationLevel()); + ret.addPass(std::move(pipeline)); + } + + // Defining the mapping + RuleSet rule_set; + auto factory = + RuleFactory(rule_set, profile.getQubitAllocationManager(), profile.getResultAllocationManager()); + factory.usingConfiguration(ptr->configurationManager().get()); + + // Creating profile pass + ret.addPass(TransformationRulesPass(std::move(rule_set), config, &profile)); + }); + + registerProfileComponent( + "llvm-passes", [](LlvmPassesConfiguration const& cfg, ProfileGenerator* ptr, Profile&) { + auto pass_pipeline = cfg.passPipeline(); + if (!pass_pipeline.empty()) + { + + auto& pass_builder = ptr->passBuilder(); + auto& npm = ptr->modulePassManager(); + if (!pass_builder.parsePassPipeline(npm, pass_pipeline, false, false)) + { + throw std::runtime_error("Failed to set pass pipeline up."); + } + } + else if (cfg.alwaysInline()) + { + auto& ret = ptr->modulePassManager(); + auto& pass_builder = ptr->passBuilder(); + ret.addPass(llvm::AlwaysInlinerPass()); + + auto inliner_pass = pass_builder.buildInlinerPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None, ptr->isDebugMode()); + ret.addPass(std::move(inliner_pass)); + } + else if (!cfg.disableDefaultPipeline()) + { + auto& mpm = ptr->modulePassManager(); + + // If not explicitly disabled, we fall back to the default LLVM pipeline + auto& pass_builder = ptr->passBuilder(); + llvm::ModulePassManager pipeline1 = + pass_builder.buildPerModuleDefaultPipeline(ptr->optimisationLevel()); + mpm.addPass(std::move(pipeline1)); + + llvm::ModulePassManager pipeline2 = pass_builder.buildModuleSimplificationPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None); + mpm.addPass(std::move(pipeline2)); + } + }); + } + + DefaultProfileGenerator::DefaultProfileGenerator( + ConfigureFunction const& configure, + TransformationRulesPassConfiguration const& profile_pass_config, + LlvmPassesConfiguration const& llvm_config) + { + configurationManager().addConfig(); + + registerProfileComponent( + "transformation-rules", + [configure](TransformationRulesPassConfiguration const& config, ProfileGenerator* ptr, Profile& profile) { + auto& ret = ptr->modulePassManager(); + + // Default optimisation pipeline + if (config.shouldSimplifyPriorTransform()) + { + auto& pass_builder = ptr->passBuilder(); + llvm::ModulePassManager pipeline = + pass_builder.buildPerModuleDefaultPipeline(ptr->optimisationLevel()); + ret.addPass(std::move(pipeline)); + } + + // Defining the mapping + RuleSet rule_set; + auto factory = + RuleFactory(rule_set, profile.getQubitAllocationManager(), profile.getResultAllocationManager()); + configure(rule_set); + + // Creating profile pass + ret.addPass(TransformationRulesPass(std::move(rule_set), config, &profile)); + }); + + registerProfileComponent( + "llvm-passes", [](LlvmPassesConfiguration const& cfg, ProfileGenerator* ptr, Profile&) { + auto pass_pipeline = cfg.passPipeline(); + if (!pass_pipeline.empty()) + { + + auto& pass_builder = ptr->passBuilder(); + auto& npm = ptr->modulePassManager(); + if (!pass_builder.parsePassPipeline(npm, pass_pipeline, false, false)) + { + throw std::runtime_error("Failed to set pass pipeline up."); + } + } + else if (cfg.alwaysInline()) + { + auto& ret = ptr->modulePassManager(); + auto& pass_builder = ptr->passBuilder(); + ret.addPass(llvm::AlwaysInlinerPass()); + + auto inliner_pass = pass_builder.buildInlinerPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None, ptr->isDebugMode()); + ret.addPass(std::move(inliner_pass)); + } + else if (!cfg.disableDefaultPipeline()) + { + auto& mpm = ptr->modulePassManager(); + + // If not explicitly disabled, we fall back to the default LLVM pipeline + auto& pass_builder = ptr->passBuilder(); + llvm::ModulePassManager pipeline1 = + pass_builder.buildPerModuleDefaultPipeline(ptr->optimisationLevel()); + mpm.addPass(std::move(pipeline1)); + + llvm::ModulePassManager pipeline2 = pass_builder.buildModuleSimplificationPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None); + mpm.addPass(std::move(pipeline2)); + } + }); + + configurationManager().setConfig(profile_pass_config); + configurationManager().setConfig(llvm_config); + } + + TransformationRulesPassConfiguration const& DefaultProfileGenerator::ruleTransformationConfig() const + { + return configurationManager().get(); + } + + LlvmPassesConfiguration const& DefaultProfileGenerator::llvmPassesConfig() const + { + return configurationManager().get(); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/DefaultProfileGenerator.hpp b/src/Passes/Source/Generators/DefaultProfileGenerator.hpp new file mode 100644 index 0000000000..096796ebdb --- /dev/null +++ b/src/Passes/Source/Generators/DefaultProfileGenerator.hpp @@ -0,0 +1,52 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Generators/LlvmPassesConfiguration.hpp" +#include "Generators/ProfileGenerator.hpp" +#include "Rules/FactoryConfig.hpp" +#include "Rules/RuleSet.hpp" +#include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + /// DefaultProfileGenerator defines a profile that configures the rule set used by the Profile + /// pass. This profile is useful for generating dynamic profiles and is well suited for testing + /// purposes or YAML configured transformation of the IR. + class DefaultProfileGenerator : public ProfileGenerator + { + public: + using ConfigureFunction = std::function; ///< Function type that configures a rule set. + + /// Default constructor. This constructor adds components for rule transformation and LLVM passes. + /// These are configurable through the corresponding configuration classes which can be access + /// through the configuration manager. + DefaultProfileGenerator(); + + /// The constructor takes a lambda function which configures the rule set. This + /// function is invoked during the creation of the generation module. This constructor + /// further overrides the default configuration + explicit DefaultProfileGenerator( + ConfigureFunction const& configure, + TransformationRulesPassConfiguration const& profile_pass_config = + TransformationRulesPassConfiguration::createDisabled(), + LlvmPassesConfiguration const& llvm_config = LlvmPassesConfiguration()); + + // Shorthand notation to access configurations + // + + /// Returns a constant reference to the rule transformation configuration. + TransformationRulesPassConfiguration const& ruleTransformationConfig() const; + + /// Returns a constant reference to the LLVM passes configuration. + LlvmPassesConfiguration const& llvmPassesConfig() const; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/LlvmPassesConfiguration.cpp b/src/Passes/Source/Generators/LlvmPassesConfiguration.cpp new file mode 100644 index 0000000000..002b5167a8 --- /dev/null +++ b/src/Passes/Source/Generators/LlvmPassesConfiguration.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Generators/LlvmPassesConfiguration.hpp" + +namespace microsoft +{ +namespace quantum +{ + + LlvmPassesConfiguration::LlvmPassesConfiguration() = default; + + void LlvmPassesConfiguration::setup(ConfigurationManager& config) + { + config.setSectionName("LLVM Passes", "Configuration of LLVM passes."); + config.addParameter(always_inline_, "always-inline", "Aggressively inline function calls."); + config.addParameter( + default_pipeline_is_disabled_, "disable-default-pipeline", "Disables the the default pipeline."); + + config.addParameter(pass_pipeline_, "passes", "LLVM passes pipeline to use upon applying this component."); + } + + LlvmPassesConfiguration LlvmPassesConfiguration::createDisabled() + { + LlvmPassesConfiguration ret; + ret.always_inline_ = false; + ret.pass_pipeline_ = ""; + ret.default_pipeline_is_disabled_ = true; + return ret; + } + + bool LlvmPassesConfiguration::alwaysInline() const + { + return always_inline_; + } + + bool LlvmPassesConfiguration::disableDefaultPipeline() const + { + return default_pipeline_is_disabled_; + } + + std::string LlvmPassesConfiguration::passPipeline() const + { + return pass_pipeline_; + } + + bool LlvmPassesConfiguration::isDisabled() const + { + return always_inline_ == false && pass_pipeline_ == ""; + } + + bool LlvmPassesConfiguration::operator==(LlvmPassesConfiguration const& ref) const + { + return always_inline_ == ref.always_inline_; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/LlvmPassesConfiguration.hpp b/src/Passes/Source/Generators/LlvmPassesConfiguration.hpp new file mode 100644 index 0000000000..793b6a7244 --- /dev/null +++ b/src/Passes/Source/Generators/LlvmPassesConfiguration.hpp @@ -0,0 +1,59 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" + +namespace microsoft +{ +namespace quantum +{ + + class LlvmPassesConfiguration + { + public: + // Default constructor which sets the standard pipeline. + LlvmPassesConfiguration(); + + // Setup and pre-fabricated configurations + + /// Setup function that registers the different LLVM passes available via LLVM component. + void setup(ConfigurationManager& config); + + /// Static function creates a new configuration where all transformations/validation requirements + /// are disabled. + static LlvmPassesConfiguration createDisabled(); + + // Configuration interpretation + // + + /// Returns true if the configuration disables all effects of this component. The effect of this + /// function being true is that registered component should have no effect on transformation + /// and/or validation of the QIR. + bool isDisabled() const; + + /// Compares equality of two configurations + bool operator==(LlvmPassesConfiguration const& ref) const; + + // Flags and options + // + + /// Whether or not the LLVM AlwaysInline pass should be added to the profile. + bool alwaysInline() const; + + /// Whether or not the default LLVM pipeline is disabled. + bool disableDefaultPipeline() const; + + std::string passPipeline() const; + + private: + // Variables that enables or disables the adding of specific passes + // + + bool always_inline_{false}; ///< Whether or not LLVM component should inline. + bool default_pipeline_is_disabled_{false}; ///< Whether or not the default pipeline is disabled + std::string pass_pipeline_{""}; ///< Opt compatible LLVM passes pipeline + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/ProfileGenerator.cpp b/src/Passes/Source/Generators/ProfileGenerator.cpp new file mode 100644 index 0000000000..1dc83682c2 --- /dev/null +++ b/src/Passes/Source/Generators/ProfileGenerator.cpp @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/ProfileGenerator.hpp" +#include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" +#include "ValidationPass/ValidationPassConfiguration.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + Profile ProfileGenerator::newProfile(String const& name, OptimizationLevel const& optimisation_level, bool debug) + { + auto qubit_allocation_manager = BasicAllocationManager::createNew(); + auto result_allocation_manager = BasicAllocationManager::createNew(); + + auto cfg = configuration_manager_.get(); + qubit_allocation_manager->setReuseRegisters(cfg.shouldReuseQubits()); + result_allocation_manager->setReuseRegisters(cfg.shouldReuseResults()); + + // Creating profile + // TODO(tfr): Set target machine + Profile ret{name, debug, nullptr, qubit_allocation_manager, result_allocation_manager}; + + auto module_pass_manager = createGenerationModulePassManager(ret, optimisation_level, debug); + + ret.setModulePassManager(std::move(module_pass_manager)); + + // Creating validator + auto validator = std::make_unique(configuration_manager_.get(), debug); + ret.setValidator(std::move(validator)); + + return ret; + } + + llvm::ModulePassManager ProfileGenerator::createGenerationModulePassManager( + Profile& profile, + OptimizationLevel const& optimisation_level, + bool debug) + { + auto& pass_builder = profile.passBuilder(); + llvm::ModulePassManager ret{}; + + module_pass_manager_ = &ret; + pass_builder_ = &pass_builder; + optimisation_level_ = optimisation_level; + debug_ = debug; + + for (auto& c : components_) + { + if (debug) + { + llvm::outs() << "Setting " << c.first << " up\n"; + } + + c.second(this, profile); + } + + return ret; + } + + llvm::ModulePassManager ProfileGenerator::createValidationModulePass(PassBuilder&, OptimizationLevel const&, bool) + { + throw std::runtime_error("Validation is not supported yet."); + } + + llvm::ModulePassManager& ProfileGenerator::modulePassManager() + { + return *module_pass_manager_; + } + + llvm::PassBuilder& ProfileGenerator::passBuilder() + { + return *pass_builder_; + } + + ConfigurationManager& ProfileGenerator::configurationManager() + { + return configuration_manager_; + } + + ConfigurationManager const& ProfileGenerator::configurationManager() const + { + return configuration_manager_; + } + + ProfileGenerator::OptimizationLevel ProfileGenerator::optimisationLevel() const + { + return optimisation_level_; + } + + bool ProfileGenerator::isDebugMode() const + { + return debug_; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/ProfileGenerator.hpp b/src/Passes/Source/Generators/ProfileGenerator.hpp new file mode 100644 index 0000000000..5c36224041 --- /dev/null +++ b/src/Passes/Source/Generators/ProfileGenerator.hpp @@ -0,0 +1,133 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "Profile/Profile.hpp" +#include "QatTypes/QatTypes.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + class ProfileGenerator + { + public: + // LLVM types + // + using PassBuilder = llvm::PassBuilder; + using OptimizationLevel = PassBuilder::OptimizationLevel; + using FunctionAnalysisManager = llvm::FunctionAnalysisManager; + + /// Setup function that uses a configuration type R to + /// configure the profile and/or generator. + template using SetupFunction = std::function; + + /// Wrapper function type for invoking the profile setup function + using SetupFunctionWrapper = std::function; + + /// List of components to be configured. + using Components = std::vector>; + + // Construction, moves and copies + // + + ProfileGenerator() = default; + ~ProfileGenerator() = default; + ProfileGenerator(ProfileGenerator const&) = delete; + ProfileGenerator(ProfileGenerator&&) = delete; + ProfileGenerator& operator=(ProfileGenerator const&) = delete; + ProfileGenerator& operator=(ProfileGenerator&&) = delete; + + // Profile generation interface + // + + /// Reference to configuration manager. This property allows to access and modify configurations + /// of the generator. This property is intended for managing the configuration. + ConfigurationManager& configurationManager(); + + /// Constant reference to the configuration manager. This property allows read access to the + /// configuration manager and is intended for profile generation. + ConfigurationManager const& configurationManager() const; + + /// Creates a new profile based on the registered components, optimisation level and debug + /// requirements. The returned profile can be applied to an IR to transform it in accordance with + /// the configurations given. + Profile newProfile(String const& name, OptimizationLevel const& optimisation_level, bool debug); + + // Defining the generator + // + + /// Registers a new profile component with a given configuration R. The profile component is given + /// a name and a setup function which is responsible for configuring the profile in accordance + /// with the configuration. + template void registerProfileComponent(String const& id, SetupFunction setup); + + // Support properties for generators + // + + /// Returns the module pass manager. + llvm::ModulePassManager& modulePassManager(); + + /// Returns the pass builder. + llvm::PassBuilder& passBuilder(); + + /// Returns the optimisation level. + OptimizationLevel optimisationLevel() const; + + /// Flag indicating whether we are operating in debug mode or not. + bool isDebugMode() const; + + protected: + /// Internal function that creates a module pass for QIR transformation. The module pass is + /// defined through the profile, the optimisation level and whether or not we are in debug mode. + llvm::ModulePassManager createGenerationModulePassManager( + Profile& profile, + OptimizationLevel const& optimisation_level, + bool debug); + + /// Internal function that creates a module pass for QIR validation. At the moment, this function + /// is a placeholder for future functionality. + llvm::ModulePassManager createValidationModulePass( + PassBuilder& pass_builder, + OptimizationLevel const& optimisation_level, + bool debug); + + private: + ConfigurationManager configuration_manager_; ///< Holds the configuration that defines the profile + Components components_; ///< List of registered components that configures the profile + + /// Pointer to the module pass manager the profile will use + llvm::ModulePassManager* module_pass_manager_{nullptr}; + + /// Pointer to the pass builder the profile is based on + llvm::PassBuilder* pass_builder_{nullptr}; + + /// Optimisation level used by LLVM + OptimizationLevel optimisation_level_{OptimizationLevel::O0}; + + /// Whether or not we are in debug mode + bool debug_{false}; + }; + + template void ProfileGenerator::registerProfileComponent(String const& id, SetupFunction setup) + { + configuration_manager_.addConfig(id); + + auto setup_wrapper = [setup](ProfileGenerator* ptr, Profile& profile) { + if (ptr->configuration_manager_.isActive()) + { + auto& config = ptr->configuration_manager_.get(); + + setup(config, ptr, profile); + } + }; + + components_.push_back({id, std::move(setup_wrapper)}); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Generators/Tests/Unit/main.cpp b/src/Passes/Source/Generators/Tests/Unit/main.cpp new file mode 100644 index 0000000000..abdf40f461 --- /dev/null +++ b/src/Passes/Source/Generators/Tests/Unit/main.cpp @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Generators/LlvmPassesConfiguration.hpp" +#include "Rules/FactoryConfig.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" +#include "gtest/gtest.h" + +using namespace microsoft::quantum; +using GeneratorPtr = std::shared_ptr; +namespace +{ +class ExposedDefaultProfileGenerator : public DefaultProfileGenerator +{ + public: + using DefaultProfileGenerator::createGenerationModulePassManager; + using DefaultProfileGenerator::createValidationModulePass; + using DefaultProfileGenerator::DefaultProfileGenerator; +}; + +class TestAnalysis +{ + public: + TestAnalysis(TestAnalysis const&) = delete; + TestAnalysis(TestAnalysis&&) = default; + ~TestAnalysis() = default; + explicit TestAnalysis(bool debug = false) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + { + + // Creating a full pass builder and registering each of the + // components to make them accessible to the developer. + pass_builder_.registerModuleAnalyses(module_analysis_manager_); + pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_.registerFunctionAnalyses(function_analysis_manager_); + pass_builder_.registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_.crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + } + + llvm::PassBuilder& passBuilder() + { + return pass_builder_; + } + + llvm::LoopAnalysisManager& loopAnalysisManager() + { + return loop_analysis_manager_; + } + + llvm::FunctionAnalysisManager& functionAnalysisManager() + { + return function_analysis_manager_; + } + + llvm::CGSCCAnalysisManager& gsccAnalysisManager() + { + return gscc_analysis_manager_; + } + + llvm::ModuleAnalysisManager& moduleAnalysisManager() + { + return module_analysis_manager_; + } + + private: + // Objects used to run a set of passes + // + + llvm::PassBuilder pass_builder_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; +}; +} // namespace + +TEST(GeneratorsTestSuite, ConfigureFunction) +{ + Profile profile{"test", false}; + uint64_t call_count{0}; + auto configure = [&call_count](RuleSet&) { ++call_count; }; + auto generator = std::make_shared(configure); + + TestAnalysis test; + + auto module_pass_manager = + generator->createGenerationModulePassManager(profile, llvm::PassBuilder::OptimizationLevel::O0, false); + + EXPECT_EQ(call_count, 1); + EXPECT_TRUE(generator->ruleTransformationConfig().isDisabled()); + EXPECT_TRUE(generator->llvmPassesConfig().isDisabled()); +} + +TEST(GeneratorsTestSuite, ConfigurationManager) +{ + Profile profile{"test", false}; + auto generator = std::make_shared(); + ConfigurationManager& configuration_manager = generator->configurationManager(); + configuration_manager.addConfig(); + + TestAnalysis test; + + auto module_pass_manager = + generator->createGenerationModulePassManager(profile, llvm::PassBuilder::OptimizationLevel::O0, false); + + EXPECT_EQ(generator->ruleTransformationConfig(), TransformationRulesPassConfiguration()); + EXPECT_EQ(generator->llvmPassesConfig(), LlvmPassesConfiguration()); + EXPECT_FALSE(generator->ruleTransformationConfig().isDisabled()); +} diff --git a/src/Passes/Source/Llvm/Llvm.hpp b/src/Passes/Source/Llvm/Llvm.hpp new file mode 100644 index 0000000000..af11f8e764 --- /dev/null +++ b/src/Passes/Source/Llvm/Llvm.hpp @@ -0,0 +1,85 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Weverything" +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wpedantic" +#pragma clang diagnostic ignored "-Werror" +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wreturn-std-move" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wunused-parameter" +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Weverything" +#endif + +// Passes +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" + +// Building +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" + +// Reader tool +#include "llvm/IRReader/IRReader.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Transforms/IPO/Inliner.h" +#include "llvm/Transforms/Scalar/LoopUnrollPass.h" + +// Profiles +#include "llvm/LinkAllPasses.h" +#include "llvm/Transforms/Scalar/ADCE.h" +#include "llvm/Transforms/Scalar/DCE.h" + +// Const folding +#include "llvm/Analysis/ConstantFolding.h" + +// Linking +#include "llvm/Linker/Linker.h" + +// Bitcode output +#include "llvm/Bitcode/BitcodeWriter.h" + +/// Initialization + +#include "llvm/InitializePasses.h" +#include "llvm/LinkAllIR.h" +#include "llvm/LinkAllPasses.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif diff --git a/src/Passes/Source/Logging/CommentLogger.cpp b/src/Passes/Source/Logging/CommentLogger.cpp new file mode 100644 index 0000000000..524be18561 --- /dev/null +++ b/src/Passes/Source/Logging/CommentLogger.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/CommentLogger.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + void CommentLogger::debug(String const& message) + { + llvm::errs() << "debug - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " << message + << "\n"; + } + + void CommentLogger::info(String const& message) + { + llvm::errs() << "info - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " << message + << "\n"; + } + + void CommentLogger::warning(String const& message) + { + llvm::errs() << "warning - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " + << message << "\n"; + } + + void CommentLogger::error(String const& message) + { + llvm::errs() << "error - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " << message + << "\n"; + } + + void CommentLogger::internalError(String const& message) + { + llvm::errs() << "internal error - " << location_name_ << ":" << location_row_ << "," << location_col_ << " - " + << message << "\n"; + } + + void CommentLogger::setLocation(String const& name, uint64_t row, uint64_t col) + { + location_name_ = name; + location_row_ = row; + location_col_ = col; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/CommentLogger.hpp b/src/Passes/Source/Logging/CommentLogger.hpp new file mode 100644 index 0000000000..78705551b7 --- /dev/null +++ b/src/Passes/Source/Logging/CommentLogger.hpp @@ -0,0 +1,46 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Concrete ILogger implementation that prints all messages as IR comments to llvm::errs(). + class CommentLogger : public ILogger + { + public: + // Interface implementation + // + + /// Adds a debug message to the list. + void debug(String const& message) override; + + /// Adds an info message to the list. + void info(String const& message) override; + + /// Adds a warning message to the list. + void warning(String const& message) override; + + /// Adds an error message to the list. + void error(String const& message) override; + + /// Adds an internal error message to the list. + void internalError(String const& message) override; + + /// Function that allows to set the current location. + void setLocation(String const& name, uint64_t row, uint64_t col) override; + + private: + String location_name_{""}; + uint64_t location_row_{0}; + uint64_t location_col_{0}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.cpp b/src/Passes/Source/Logging/ILogger.cpp new file mode 100644 index 0000000000..be896e7f01 --- /dev/null +++ b/src/Passes/Source/Logging/ILogger.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + ILogger::~ILogger() = default; +} +} // namespace microsoft diff --git a/src/Passes/Source/Logging/ILogger.hpp b/src/Passes/Source/Logging/ILogger.hpp new file mode 100644 index 0000000000..76a0dce977 --- /dev/null +++ b/src/Passes/Source/Logging/ILogger.hpp @@ -0,0 +1,57 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "QatTypes/QatTypes.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Logger interface to allow the collection of different types of messages during QIR + /// transformation and/or validation. + class ILogger + { + public: + // Constructors, copy and move operators and destructors + // + + ILogger() = default; + ILogger(ILogger const&) = default; + ILogger(ILogger&&) = default; + ILogger& operator=(ILogger const&) = default; + ILogger& operator=(ILogger&&) = default; + + virtual ~ILogger(); + + // Abstract interface methods + // + + /// Reports a debug message. + virtual void debug(String const& message) = 0; + + /// Reports an info message. + virtual void info(String const& message) = 0; + + /// Reports a warning message. + virtual void warning(String const& message) = 0; + + /// Reports an error message. + virtual void error(String const& message) = 0; + + /// Reports an internal error message. + virtual void internalError(String const& message) = 0; + + /// Sets the current location. Importantly, the location can be set independently of the reported + /// messages. This allows one to update the location upon updating the cursor position without + /// having to worry about keeping a copy of the location to pass when reporting messages. + /// The most obvious case of this is file path (name) with a line and character (row, col). + virtual void setLocation(String const& name, uint64_t row, uint64_t col) = 0; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/LogCollection.cpp b/src/Passes/Source/Logging/LogCollection.cpp new file mode 100644 index 0000000000..9e59b90316 --- /dev/null +++ b/src/Passes/Source/Logging/LogCollection.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/LogCollection.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + void LogCollection::debug(String const& message) + { + messages_.push_back({Type::Debug, current_location_, message}); + } + + void LogCollection::info(String const& message) + { + messages_.push_back({Type::Info, current_location_, message}); + } + + void LogCollection::warning(String const& message) + { + messages_.push_back({Type::Warning, current_location_, message}); + } + + void LogCollection::error(String const& message) + { + messages_.push_back({Type::Error, current_location_, message}); + } + + void LogCollection::internalError(String const& message) + { + messages_.push_back({Type::InternalError, current_location_, message}); + } + + void LogCollection::setLocation(String const& name, uint64_t row, uint64_t col) + { + current_location_.name = name; + current_location_.row = row; + current_location_.col = col; + } + + LogCollection::Messages const& LogCollection::messages() const + { + return messages_; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Logging/LogCollection.hpp b/src/Passes/Source/Logging/LogCollection.hpp new file mode 100644 index 0000000000..957de3a316 --- /dev/null +++ b/src/Passes/Source/Logging/LogCollection.hpp @@ -0,0 +1,78 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Concrete ILogger implementation that collects all messages and their corresponding location in a + /// list that can be traversed later on. + class LogCollection : public ILogger + { + public: + /// Class that holds the location of where the incident happened. + struct Location + { + String name{}; + uint64_t row{0}; + uint64_t col{0}; + }; + + /// Enum description what type of information we are conveying. + enum class Type + { + Debug, + Info, + Warning, + Error, + InternalError, + }; + + /// Struct to hold a message together with its type and location + struct Message + { + Type type; + Location location; + String message; + }; + + /// List of messages defined as alias. + using Messages = std::vector; + + // Interface implementation + // + + /// Adds a debug message to the list. + void debug(String const& message) override; + + /// Adds an info message to the list. + void info(String const& message) override; + + /// Adds a warning message to the list. + void warning(String const& message) override; + + /// Adds an error message to the list. + void error(String const& message) override; + + /// Adds an internal error message to the list. + void internalError(String const& message) override; + + /// Function that allows to set the current location. + void setLocation(String const& name, uint64_t row, uint64_t col) override; + + /// Accessor to the messages + Messages const& messages() const; + + private: + Location current_location_{}; ///< Holds current location. + Messages messages_; ///< All messages emitted. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ModuleLoader/ModuleLoader.hpp b/src/Passes/Source/ModuleLoader/ModuleLoader.hpp new file mode 100644 index 0000000000..b83983004d --- /dev/null +++ b/src/Passes/Source/ModuleLoader/ModuleLoader.hpp @@ -0,0 +1,133 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "QatTypes/QatTypes.hpp" +#include "RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + class ModuleLoader + { + public: + using Module = llvm::Module; + using Linker = llvm::Linker; + using SMDiagnostic = llvm::SMDiagnostic; + + explicit ModuleLoader(Module* final_module) + : final_module_{final_module} + , linker_{*final_module} + + { + } + + bool addModule(std::unique_ptr&& module, String const& filename = "unknown") + { + if (llvm::verifyModule(*module, &llvm::errs())) + { + llvm::errs() << filename << ": " + << "input module is broken!\n"; + return false; + } + + return !linker_.linkInModule(std::move(module), Linker::Flags::None); + } + + bool addIrFile(String const& filename) + { + + // Loading module + SMDiagnostic err; + std::unique_ptr module = llvm::parseIRFile(filename, err, final_module_->getContext()); + if (!module) + { + llvm::errs() << "Failed to load " << filename << "\n"; + return false; + } + + // Transforming module + SingleModuleTransformation transformation; + if (!transformation.apply(module.get())) + { + llvm::errs() << "Failed to transform " << filename << "\n"; + return false; + } + + // Linking + return addModule(std::move(module), filename); + } + + private: + Module* final_module_; + Linker linker_; + + // Single Module Transformation + // + + class SingleModuleTransformation + { + public: + using PassBuilder = llvm::PassBuilder; + using OptimizationLevel = PassBuilder::OptimizationLevel; + using FunctionAnalysisManager = llvm::FunctionAnalysisManager; + + explicit SingleModuleTransformation( + OptimizationLevel const& optimisation_level = OptimizationLevel::O0, + bool debug = false) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , optimisation_level_{optimisation_level} + , debug_{debug} + { + + pass_builder_.registerModuleAnalyses(module_analysis_manager_); + pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_.registerFunctionAnalyses(function_analysis_manager_); + pass_builder_.registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_.crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, + module_analysis_manager_); + + module_pass_manager_.addPass(RemoveDisallowedAttributesPass()); + } + + bool apply(llvm::Module* module) + { + module_pass_manager_.run(*module, module_analysis_manager_); + + if (llvm::verifyModule(*module, &llvm::errs())) + { + return false; + } + + return true; + } + + bool isDebugMode() const + { + return debug_; + } + + private: + llvm::PassBuilder pass_builder_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + llvm::ModulePassManager module_pass_manager_{}; + OptimizationLevel optimisation_level_{}; + bool debug_{false}; + }; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Profile/Profile.cpp b/src/Passes/Source/Profile/Profile.cpp new file mode 100644 index 0000000000..0c43103250 --- /dev/null +++ b/src/Passes/Source/Profile/Profile.cpp @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Profile/Profile.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + Profile::Profile( + String const& name, + bool debug, + llvm::TargetMachine* target_machine, + AllocationManagerPtr qubit_allocation_manager, + AllocationManagerPtr result_allocation_manager) + : name_{name} + , loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , pass_instrumentation_callbacks_{std::make_unique()} + , standard_instrumentations_{std::make_unique()} + , qubit_allocation_manager_{std::move(qubit_allocation_manager)} + , result_allocation_manager_{std::move(result_allocation_manager)} + , validator_{std::make_unique(ValidationPassConfiguration(), debug)} + { + bool verify_each_pass = false; + standard_instrumentations_->registerCallbacks(*pass_instrumentation_callbacks_); + + // TODO(tfr): Parameterize + // pipeline_tuning_options_.LoopUnrolling = !DisableLoopUnrolling; + // pipeline_tuning_options_.Coroutines = Coroutines; + + pass_builder_ = std::make_unique( + target_machine, pipeline_tuning_options_, pgo_options_, pass_instrumentation_callbacks_.get()); + + registerEPCallbacks(verify_each_pass, debug); + + // Creating a full pass builder and registering each of the + // components to make them accessible to the developer. + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_->crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + } + + void Profile::registerEPCallbacks(bool verify_each_pass, bool debug) + { + + if (tryParsePipelineText(*pass_builder_, peephole_ep_pipeline_)) + { + pass_builder_->registerPeepholeEPCallback( + [this, verify_each_pass, + debug](llvm::FunctionPassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse PeepholeEP pipeline: "); + error_safeguard( + pass_builder_->parsePassPipeline(pass_manager, peephole_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, late_loop_optimizations_ep_pipeline_)) + { + pass_builder_->registerLateLoopOptimizationsEPCallback( + [this, verify_each_pass, + debug](llvm::LoopPassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse LateLoopOptimizationsEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, late_loop_optimizations_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, loop_optimizer_end_ep_pipeline_)) + { + pass_builder_->registerLoopOptimizerEndEPCallback( + [this, verify_each_pass, + debug](llvm::LoopPassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse LoopOptimizerEndEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, loop_optimizer_end_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, scalar_optimizer_late_ep_pipeline_)) + { + pass_builder_->registerScalarOptimizerLateEPCallback( + [this, verify_each_pass, + debug](llvm::FunctionPassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse ScalarOptimizerLateEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, scalar_optimizer_late_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, cgscc_optimizer_late_ep_pipeline_)) + { + pass_builder_->registerCGSCCOptimizerLateEPCallback( + [this, verify_each_pass, + debug](llvm::CGSCCPassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse CGSCCOptimizerLateEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, cgscc_optimizer_late_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, vectorizer_start_ep_pipeline_)) + { + pass_builder_->registerVectorizerStartEPCallback( + [this, verify_each_pass, + debug](llvm::FunctionPassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse VectorizerStartEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, vectorizer_start_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, pipeline_start_ep_pipeline_)) + { + pass_builder_->registerPipelineStartEPCallback( + [this, verify_each_pass, debug](llvm::ModulePassManager& pass_manager) { + llvm::ExitOnError error_safeguard("Unable to parse PipelineStartEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, pipeline_start_ep_pipeline_, verify_each_pass, debug)); + }); + } + + if (tryParsePipelineText(*pass_builder_, optimizer_last_ep_pipeline_)) + { + pass_builder_->registerOptimizerLastEPCallback( + [this, verify_each_pass, + debug](llvm::ModulePassManager& pass_manager, llvm::PassBuilder::OptimizationLevel) { + llvm::ExitOnError error_safeguard("Unable to parse OptimizerLastEP pipeline: "); + error_safeguard(pass_builder_->parsePassPipeline( + pass_manager, optimizer_last_ep_pipeline_, verify_each_pass, debug)); + }); + } + } + + void Profile::apply(llvm::Module& module) + { + module_pass_manager_.run(module, module_analysis_manager_); + } + + bool Profile::verify(llvm::Module& module) + { + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); + return !result.IRBroken; + } + + bool Profile::validate(llvm::Module& module) + { + return validator_->validate(module); + } + + String const& Profile::name() const + { + return name_; + } + + Profile::AllocationManagerPtr Profile::getQubitAllocationManager() + { + return qubit_allocation_manager_; + } + + Profile::AllocationManagerPtr Profile::getResultAllocationManager() + { + return result_allocation_manager_; + } + + void Profile::setModulePassManager(llvm::ModulePassManager&& manager) + { + module_pass_manager_ = std::move(manager); + } + + void Profile::setValidator(ValidatorPtr&& validator) + { + validator_ = std::move(validator); + } + + llvm::PassBuilder& Profile::passBuilder() + { + return *pass_builder_; + } + llvm::LoopAnalysisManager& Profile::loopAnalysisManager() + { + return loop_analysis_manager_; + } + llvm::FunctionAnalysisManager& Profile::functionAnalysisManager() + { + return function_analysis_manager_; + } + llvm::CGSCCAnalysisManager& Profile::gsccAnalysisManager() + { + return gscc_analysis_manager_; + } + llvm::ModuleAnalysisManager& Profile::moduleAnalysisManager() + { + return module_analysis_manager_; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Profile/Profile.hpp b/src/Passes/Source/Profile/Profile.hpp new file mode 100644 index 0000000000..0e3a1ea09d --- /dev/null +++ b/src/Passes/Source/Profile/Profile.hpp @@ -0,0 +1,164 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/AllocationManager.hpp" +#include "AllocationManager/IAllocationManager.hpp" +#include "QatTypes/QatTypes.hpp" +#include "Validator/Validator.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + class ProfileGenerator; + + /// Profile class that defines a set of rules which constitutes the profile definition. Each of the + /// rules can be used to transform a generic QIR and/or validate that the QIR is compliant with said + /// rule. + class Profile + { + public: + /// Allocation manager pointer type. Used to reference to concrete allocation manager + /// implementations which defines the allocation logic of the profile. + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; + + /// Validator class used to check that an IR fulfils a given specification + using ValidatorPtr = Validator::ValidatorPtr; + + // Constructors + // + + explicit Profile( + String const& name, + bool debug, + llvm::TargetMachine* target_machine = nullptr, + AllocationManagerPtr qubit_allocation_manager = BasicAllocationManager::createNew(), + AllocationManagerPtr result_allocation_manager = BasicAllocationManager::createNew()); + + // Default construction not allowed as this leads to invalid configuration of the allocation + // managers. + + Profile() = delete; + Profile(Profile const&) = delete; + Profile(Profile&&) = default; + Profile& operator=(Profile const&) = delete; + Profile& operator=(Profile&&) = default; + ~Profile() = default; + + // Profile methods + // + + /// Applies the profile to a module. + void apply(llvm::Module& module); + + /// Verifies that a module is a valid LLVM IR. + bool verify(llvm::Module& module); + + /// Validates that a module complies with the specified QIR profile. + bool validate(llvm::Module& module); + + AllocationManagerPtr getQubitAllocationManager(); + AllocationManagerPtr getResultAllocationManager(); + + String const& name() const; + + protected: + // Ensuring that ProfileGenerator has access to following protected functions. + friend class ProfileGenerator; + + /// Sets the module pass manager used for the transformation of the IR. + void setModulePassManager(llvm::ModulePassManager&& manager); + + /// Sets the validator + void setValidator(ValidatorPtr&& validator); + + /// Returns a reference to the pass builder. + llvm::PassBuilder& passBuilder(); + + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager& loopAnalysisManager(); + + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager& functionAnalysisManager(); + + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager& gsccAnalysisManager(); + + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager& moduleAnalysisManager(); + + private: + using PassInstrumentationCallbacksPtr = std::unique_ptr; + using StandardInstrumentationsPtr = std::unique_ptr; + using PassBuilderPtr = std::unique_ptr; + + void registerEPCallbacks(bool verify_each_pass, bool debug); + + template + bool tryParsePipelineText(llvm::PassBuilder& pass_builder, std::string const& pipeline_options) + { + if (pipeline_options.empty()) + { + return false; + } + + PassManager pass_manager; + if (auto err = pass_builder.parsePassPipeline(pass_manager, pipeline_options)) + { + llvm::errs() << "Could not parse -" << pipeline_options << " pipeline: " << toString(std::move(err)) + << "\n"; + return false; + } + return true; + } + + /// Name of the selected profile + String name_{}; + + // LLVM logic to run the passes + // + + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + llvm::Optional pgo_options_; + PassInstrumentationCallbacksPtr pass_instrumentation_callbacks_; + StandardInstrumentationsPtr standard_instrumentations_; + llvm::PipelineTuningOptions pipeline_tuning_options_; + + PassBuilderPtr pass_builder_; + + llvm::ModulePassManager module_pass_manager_{}; + + // Allocation management + // + + /// Interface pointer to the qubit allocation manager. Mode of operation depends on the concrete + /// implementation of the manager which is swappable through the interface. + AllocationManagerPtr qubit_allocation_manager_{}; + + /// Interface pointer to the results allocation manager. Again here the manager behaviour is + /// determined by its implementation details. + AllocationManagerPtr result_allocation_manager_{}; + + /// + ValidatorPtr validator_{}; + + std::string peephole_ep_pipeline_{""}; + std::string late_loop_optimizations_ep_pipeline_{""}; + std::string loop_optimizer_end_ep_pipeline_{""}; + std::string scalar_optimizer_late_ep_pipeline_{""}; + std::string cgscc_optimizer_late_ep_pipeline_{""}; + std::string vectorizer_start_ep_pipeline_{""}; + std::string pipeline_start_ep_pipeline_{""}; + std::string optimizer_last_ep_pipeline_{""}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/QatTypes/QatTypes.hpp b/src/Passes/Source/QatTypes/QatTypes.hpp new file mode 100644 index 0000000000..445a9121b6 --- /dev/null +++ b/src/Passes/Source/QatTypes/QatTypes.hpp @@ -0,0 +1,15 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +namespace microsoft +{ +namespace quantum +{ + + using String = std::string; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp b/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp new file mode 100644 index 0000000000..2b0e242d91 --- /dev/null +++ b/src/Passes/Source/RemoveDisallowedAttributesPass/RemoveDisallowedAttributesPass.hpp @@ -0,0 +1,69 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "QatTypes/QatTypes.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class RemoveDisallowedAttributesPass : public llvm::PassInfoMixin + { + public: + RemoveDisallowedAttributesPass() + : allowed_attrs_{{static_cast("EntryPoint"), static_cast("InteropFriendly")}} + { + } + + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& /*mam*/) + { + for (auto& fnc : module) + { + std::unordered_set to_keep; + + // Finding all valid attributes + for (auto& attrset : fnc.getAttributes()) + { + for (auto& attr : attrset) + { + auto r = static_cast(attr.getAsString()); + + // Stripping quotes + if (r.size() >= 2 && r[0] == '"' && r[r.size() - 1] == '"') + { + r = r.substr(1, r.size() - 2); + } + + // Inserting if allowed + if (allowed_attrs_.find(r) != allowed_attrs_.end()) + { + to_keep.insert(r); + } + } + } + + // Deleting every + fnc.setAttributes({}); + for (auto& attr : to_keep) + { + fnc.addFnAttr(attr); + } + } + + return llvm::PreservedAnalyses::none(); + } + + private: + std::unordered_set allowed_attrs_; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Factory.cpp b/src/Passes/Source/Rules/Factory.cpp new file mode 100644 index 0000000000..836b09b39d --- /dev/null +++ b/src/Passes/Source/Rules/Factory.cpp @@ -0,0 +1,671 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Factory.hpp" +#include "Rules/Notation/Notation.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + namespace + { + using Instruction = llvm::Instruction; + using Value = llvm::Value; + using Builder = ReplacementRule::Builder; + using Captures = ReplacementRule::Captures; + using Replacements = ReplacementRule::Replacements; + + } // namespace + + using ReplacementRulePtr = RuleFactory::ReplacementRulePtr; + using namespace microsoft::quantum::notation; + + RuleFactory::RuleFactory( + RuleSet& rule_set, + AllocationManagerPtr qubit_alloc_manager, + AllocationManagerPtr result_alloc_manager) + : rule_set_{rule_set} + , qubit_alloc_manager_{std::move(qubit_alloc_manager)} + , result_alloc_manager_{std::move(result_alloc_manager)} + { + } + + void RuleFactory::usingConfiguration(FactoryConfiguration const& config) + { + default_integer_width_ = config.defaultIntegerWidth(); + + if (config.disableReferenceCounting()) + { + disableReferenceCounting(); + } + + if (config.disableAliasCounting()) + { + disableAliasCounting(); + } + + if (config.disableStringSupport()) + { + disableStringSupport(); + } + + if (config.optimiseResultOne()) + { + optimiseResultOne(); + } + + if (config.optimiseResultZero()) + { + optimiseResultZero(); + } + + if (config.useStaticQubitArrayAllocation()) + { + useStaticQubitArrayAllocation(); + } + + if (config.useStaticQubitAllocation()) + { + useStaticQubitAllocation(); + } + + if (config.useStaticResultAllocation()) + { + useStaticResultAllocation(); + } + } + + void RuleFactory::removeFunctionCall(String const& name) + { + addRule({callByNameOnly(name), deleteInstruction()}); + } + + void RuleFactory::resolveConstantArraySizes() + { + /// Array access replacement + auto size_replacer = [](Builder&, Value* val, Captures& cap, Replacements& replacements) { + // Get the index and testing that it is a constant int + auto cst = llvm::dyn_cast(cap["size"]); + if (cst == nullptr) + { + // ... if not, we cannot perform the mapping. + return false; + } + + val->replaceAllUsesWith(cst); + replacements.push_back({llvm::dyn_cast(val), nullptr}); + + return true; + }; + llvm::errs() << "Creating pattern\n"; + + auto create_array = call("__quantum__rt__array_create_1d", "elementSize"_cap = _, "size"_cap = _); + auto get_size = call("__quantum__rt__array_get_size_1d", create_array); + + addRule({std::move(get_size), size_replacer}); + } + + void RuleFactory::inlineCallables() + { + /// Array access replacement + auto callable_replacer = [](Builder&, Value* val, Captures& captures, Replacements&) { + llvm::errs() << "FOUND CALLABLE\n"; + llvm::errs() << *val << "\n"; + llvm::errs() << "Calling " << *captures["function"] << "\n"; + return false; + }; + + auto create_callable = call("__quantum__rt__callable_create", "function"_cap = _, "size"_cap = _, _); + auto invoke = call("__quantum__rt__callable_invoke", create_callable, "args"_cap = _, "ret"_cap = _); + + addRule({std::move(invoke), callable_replacer}); + } + + void RuleFactory::useStaticQubitArrayAllocation() + { + // TODO(QAT-private-issue-32): Use weak pointers to capture allocation managers + auto qubit_alloc_manager = qubit_alloc_manager_; + + /// Allocation + auto default_iw = default_integer_width_; + auto allocation_replacer = + [default_iw, qubit_alloc_manager](Builder& builder, Value* val, Captures& cap, Replacements& replacements) { + auto cst = llvm::dyn_cast(cap["size"]); + if (cst == nullptr) + { + return false; + } + + auto ptr_type = llvm::dyn_cast(val->getType()); + if (ptr_type == nullptr) + { + return false; + } + + if (cst == nullptr) + { + return false; + } + + auto llvm_size = cst->getValue(); + auto name = val->getName().str(); + auto size = llvm_size.getZExtValue(); + auto offset = qubit_alloc_manager->allocate(name, size); + + // Creating a new index APInt that is shifted by the offset of the allocation + auto idx = llvm::APInt(default_iw, offset); + + // Computing offset + auto new_index = llvm::ConstantInt::get(builder.getContext(), idx); + + auto instr = new llvm::IntToPtrInst(new_index, ptr_type); + instr->takeName(val); + + // Replacing the instruction with new instruction + auto old_instr = llvm::dyn_cast(val); + + // Safety precaution to ensure that we are dealing with a Instruction + if (old_instr == nullptr) + { + return false; + } + + // Ensuring that we have replaced the instruction before + // identifying release + old_instr->replaceAllUsesWith(instr); + + replacements.push_back({old_instr, instr}); + return true; + }; + + /// This rule is replacing the allocate qubit array instruction + /// + /// %leftPreshared = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) + /// + /// by changing it to a constant pointer + /// + /// %leftPreshared = inttoptr i64 0 to %Array* + /// + /// In this way, we use the + + addRule({call("__quantum__rt__qubit_allocate_array", "size"_cap = _), allocation_replacer}); + + /// Array access replacement + auto access_replacer = + [qubit_alloc_manager](Builder& builder, Value* val, Captures& cap, Replacements& replacements) { + // Getting the type pointer + auto ptr_type = llvm::dyn_cast(val->getType()); + if (ptr_type == nullptr) + { + return false; + } + + // Get the index and testing that it is a constant int + auto cst = llvm::dyn_cast(cap["index"]); + if (cst == nullptr) + { + // ... if not, we cannot perform the mapping. + return false; + } + + // Computing the index by getting the current index value and offsetting by + // the offset at which the qubit array is allocated. + auto offset_cst = llvm::dyn_cast(cap["arrayName"]); + if (offset_cst == nullptr) + { + return false; + } + auto llvm_offset = offset_cst->getValue(); + auto offset = llvm_offset.getZExtValue(); + + // Creating a new index APInt that is shifted by the offset of the allocation + auto llvm_size = cst->getValue(); + auto idx = llvm::APInt(llvm_size.getBitWidth(), llvm_size.getZExtValue() + offset); + + // Computing offset + auto new_index = llvm::ConstantInt::get(builder.getContext(), idx); + + // Converting pointer + auto instr = new llvm::IntToPtrInst(new_index, ptr_type); + instr->takeName(val); + + // Replacing the instruction with new instruction + replacements.push_back({llvm::dyn_cast(val), instr}); + + // Deleting the getelement and cast operations + replacements.push_back({llvm::dyn_cast(cap["getElement"]), nullptr}); + replacements.push_back({llvm::dyn_cast(cap["cast"]), nullptr}); + + return true; + }; + + auto get_element = call( + "__quantum__rt__array_get_element_ptr_1d", intToPtr("arrayName"_cap = constInt()), + "index"_cap = constInt()); + auto cast_pattern = bitCast("getElement"_cap = get_element); + auto load_pattern = load("cast"_cap = cast_pattern); + + addRule({std::move(load_pattern), access_replacer}); + + /// Release replacement + auto deleter = deleteInstruction(); + + addRule( + {call("__quantum__rt__qubit_release_array", intToPtr("const"_cap = constInt())), + [qubit_alloc_manager, deleter](Builder& builder, Value* val, Captures& cap, Replacements& rep) { + // Recovering the qubit id + auto cst = llvm::dyn_cast(cap["const"]); + if (cst == nullptr) + { + return false; + } + auto address = cst->getValue().getZExtValue(); + + // Releasing + qubit_alloc_manager->release(address); + + // Deleting instruction + return deleter(builder, val, cap, rep); + }}); + } + + void RuleFactory::useStaticQubitAllocation() + { + auto qubit_alloc_manager = qubit_alloc_manager_; + auto default_iw = default_integer_width_; + auto allocation_replacer = + [default_iw, qubit_alloc_manager](Builder& builder, Value* val, Captures&, Replacements& replacements) { + // Getting the type pointer + auto ptr_type = llvm::dyn_cast(val->getType()); + if (ptr_type == nullptr) + { + return false; + } + + auto qubit_name = val->getName().str(); + + // Computing the index by getting the current index value and offseting by + // the offset at which the qubit array is allocated. + auto offset = qubit_alloc_manager->allocate(qubit_name); + + // Creating a new index APInt that is shifted by the offset of the allocation + auto idx = llvm::APInt(default_iw, offset); + + // Computing offset + auto new_index = llvm::ConstantInt::get(builder.getContext(), idx); + + auto instr = new llvm::IntToPtrInst(new_index, ptr_type); + instr->takeName(val); + + // Replacing the instruction with new instruction + auto old_instr = llvm::dyn_cast(val); + + // Safety precaution to ensure that we are dealing with a Instruction + if (old_instr == nullptr) + { + return false; + } + + // Ensuring that we have replaced the instruction before + // identifying release + old_instr->replaceAllUsesWith(instr); + + replacements.push_back({old_instr, instr}); + + return true; + }; + + // Dealing with qubit allocation + addRule({call("__quantum__rt__qubit_allocate"), allocation_replacer}); + + /// Release replacement + auto deleter = deleteInstruction(); + + // Handling the case where a constant integer is cast to a pointer and the pointer + // is used in a call to qubit_release: + // + // %0 = inttoptr i64 0 to %Qubit* + // call void @__quantum__rt__qubit_release(%Qubit* %0 + // + // The case of named addresses are also covered, by this pattern: + // %leftMessage = inttoptr i64 0 to %Qubit* + // call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + + addRule( + {call("__quantum__rt__qubit_release", intToPtr("const"_cap = constInt())), + [qubit_alloc_manager, deleter](Builder& builder, Value* val, Captures& cap, Replacements& rep) { + // Recovering the qubit id + auto cst = llvm::dyn_cast(cap["const"]); + if (cst == nullptr) + { + return false; + } + auto address = cst->getValue().getZExtValue(); + + // Releasing + qubit_alloc_manager->release(address); + + // Deleting instruction + return deleter(builder, val, cap, rep); + }}); + + // Handling where allocation is done by non-standard functions. In + // this rule reports an error as we cannot reliably do a mapping. + // + // %leftMessage = call %Qubit* @__non_standard_allocator() + // call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + addRule( + {call("__quantum__rt__qubit_release", "name"_cap = _), + [qubit_alloc_manager, deleter](Builder& builder, Value* val, Captures& cap, Replacements& rep) { + // Getting the name + auto name = cap["name"]->getName().str(); + + // Returning in case the name comes out empty + if (name.empty()) + { + + // TODO(tfr): report error + llvm::outs() << "FAILED due to unnamed non standard allocation:\n"; + llvm::outs() << *val << "\n\n"; + + // Deleting the instruction in order to proceed + // and trying to discover as many other errors as possible + return deleter(builder, val, cap, rep); + } + + // TODO(tfr): report error + llvm::outs() << "FAILED due to non standard allocation:\n"; + llvm::outs() << *cap["name"] << "\n"; + llvm::outs() << *val << "\n\n"; + + return deleter(builder, val, cap, rep); + } + + }); + } + + void RuleFactory::useStaticResultAllocation() + { + auto result_alloc_manager = result_alloc_manager_; + auto default_iw = default_integer_width_; + auto replace_measurement = [default_iw, result_alloc_manager]( + Builder& builder, Value* val, Captures& cap, Replacements& replacements) { + // Getting the type pointer + auto ptr_type = llvm::dyn_cast(val->getType()); + if (ptr_type == nullptr) + { + return false; + } + + // Computing the index by getting the current index value and offseting by + // the offset at which the qubit array is allocated. + auto offset = result_alloc_manager->allocate(); + + // Creating a new index APInt that is shifted by the offset of the allocation + auto idx = llvm::APInt(default_iw, offset); + + // Computing offset + auto new_index = llvm::ConstantInt::get(builder.getContext(), idx); + + auto instr = new llvm::IntToPtrInst(new_index, ptr_type); + + if (instr == nullptr) + { + return false; + } + + instr->takeName(val); + + auto orig_instr = llvm::dyn_cast(val); + if (orig_instr == nullptr) + { + return false; + } + + auto module = orig_instr->getModule(); + auto fnc = module->getFunction("__quantum__qis__mz__body"); + + std::vector arguments; + arguments.push_back(cap["qubit"]); + arguments.push_back(instr); + + if (!fnc) + { + std::vector types; + types.resize(arguments.size()); + for (uint64_t i = 0; i < types.size(); ++i) + { + types[i] = arguments[i]->getType(); + } + + auto return_type = llvm::Type::getVoidTy(val->getContext()); + + llvm::FunctionType* fnc_type = llvm::FunctionType::get(return_type, types, false); + fnc = llvm::Function::Create( + fnc_type, llvm::Function::ExternalLinkage, "__quantum__qis__mz__body", module); + } + + // Ensuring we are inserting after the instruction being deleted + builder.SetInsertPoint(llvm::dyn_cast(val)->getNextNode()); + + builder.CreateCall(fnc, arguments); + + // Replacing the instruction with new instruction + replacements.push_back({llvm::dyn_cast(val), instr}); + + return true; + }; + + // This rules identifies result allocations through the function "__quantum__qis__m__body". + // As an example, the following + // + // %result1 = call %Result* @__quantum__qis__m__body(%Qubit* %0) + // + // translates into + // + // %result1 = inttoptr i64 0 to %Result* + // call void @__quantum__qis__mz__body(%Qubit* %0, %Result* %result1) + + addRule({call("__quantum__qis__m__body", "qubit"_cap = _), std::move(replace_measurement)}); + } + + void RuleFactory::optimiseResultZero() + { + auto replace_branch_negative = [](Builder& builder, Value* val, Captures& cap, Replacements& replacements) { + auto cond = llvm::dyn_cast(val); + if (cond == nullptr) + { + return false; + } + auto result = cap["result"]; + // Replacing result + auto orig_instr = llvm::dyn_cast(val); + if (orig_instr == nullptr) + { + return false; + } + + auto module = orig_instr->getModule(); + auto fnc = module->getFunction("__quantum__qis__read_result__body"); + std::vector arguments; + arguments.push_back(result); + + if (!fnc) + { + std::vector types; + types.resize(arguments.size()); + for (uint64_t i = 0; i < types.size(); ++i) + { + types[i] = arguments[i]->getType(); + } + + auto return_type = llvm::Type::getInt1Ty(val->getContext()); + + llvm::FunctionType* fnc_type = llvm::FunctionType::get(return_type, types, false); + fnc = llvm::Function::Create( + fnc_type, llvm::Function::ExternalLinkage, "__quantum__qis__read_result__body", module); + } + + builder.SetInsertPoint(llvm::dyn_cast(val)); + auto new_call = builder.CreateCall(fnc, arguments); + auto new_cond = builder.CreateNot(new_call); + new_cond->takeName(cond); + + for (auto& use : cond->uses()) + { + llvm::User* user = use.getUser(); + user->setOperand(use.getOperandNo(), new_cond); + } + cond->replaceAllUsesWith(new_cond); + + // Deleting the previous condition and function to fetch one + replacements.push_back({cond, nullptr}); + replacements.push_back({cap["zero"], nullptr}); + + return true; + }; + + /* + Here is an example IR for which we want to make a match: + + %1 = call %Result* @__quantum__rt__result_get_zero() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + br i1 %2, label %then0__1, label %continue__1 + */ + + // Variations of get_one + auto get_zero = call("__quantum__rt__result_get_zero"); + addRule( + {call("__quantum__rt__result_equal", "result"_cap = _, "zero"_cap = get_zero), replace_branch_negative}); + + addRule( + {call("__quantum__rt__result_equal", "zero"_cap = get_zero, "result"_cap = _), replace_branch_negative}); + } + + void RuleFactory::optimiseResultOne() + { + auto replace_branch_positive = [](Builder& builder, Value* val, Captures& cap, Replacements& replacements) { + auto cond = llvm::dyn_cast(val); + if (cond == nullptr) + { + return false; + } + auto result = cap["result"]; + // Replacing result + auto orig_instr = llvm::dyn_cast(val); + if (orig_instr == nullptr) + { + return false; + } + + auto module = orig_instr->getModule(); + auto fnc = module->getFunction("__quantum__qis__read_result__body"); + std::vector arguments; + arguments.push_back(result); + + if (!fnc) + { + std::vector types; + types.resize(arguments.size()); + for (uint64_t i = 0; i < types.size(); ++i) + { + types[i] = arguments[i]->getType(); + } + + auto return_type = llvm::Type::getInt1Ty(val->getContext()); + + llvm::FunctionType* fnc_type = llvm::FunctionType::get(return_type, types, false); + fnc = llvm::Function::Create( + fnc_type, llvm::Function::ExternalLinkage, "__quantum__qis__read_result__body", module); + } + + builder.SetInsertPoint(llvm::dyn_cast(val)); + auto new_call = builder.CreateCall(fnc, arguments); + + new_call->takeName(cond); + + for (auto& use : cond->uses()) + { + llvm::User* user = use.getUser(); + user->setOperand(use.getOperandNo(), new_call); + } + cond->replaceAllUsesWith(new_call); + + // Deleting the previous condition and function to fetch one + replacements.push_back({cond, nullptr}); + replacements.push_back({cap["one"], nullptr}); + + return true; + }; + + /* + Here is an example IR for which we want to make a match: + + %1 = call %Result* @__quantum__rt__result_get_one() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + br i1 %2, label %then0__1, label %continue__1 + */ + + // Variations of get_one + auto get_one = call("__quantum__rt__result_get_one"); + addRule({call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = get_one), replace_branch_positive}); + + addRule({call("__quantum__rt__result_equal", "one"_cap = get_one, "result"_cap = _), replace_branch_positive}); + } + + void RuleFactory::disableReferenceCounting() + { + // removeFunctionCall("__quantum__rt__array_update_reference_count"); + removeFunctionCall("__quantum__rt__string_update_reference_count"); + removeFunctionCall("__quantum__rt__result_update_reference_count"); + } + + void RuleFactory::disableAliasCounting() + { + // removeFunctionCall("__quantum__rt__array_update_alias_count"); + removeFunctionCall("__quantum__rt__string_update_alias_count"); + removeFunctionCall("__quantum__rt__result_update_alias_count"); + } + + void RuleFactory::disableStringSupport() + { + removeFunctionCall("__quantum__rt__fail"); + removeFunctionCall("__quantum__rt__message"); + removeFunctionCall("__quantum__rt__string_update_alias_count"); + + removeFunctionCall("__quantum__rt__string_create"); + removeFunctionCall("__quantum__rt__string_get_data"); + removeFunctionCall("__quantum__rt__string_get_length"); + removeFunctionCall("__quantum__rt__string_update_reference_count"); + removeFunctionCall("__quantum__rt__string_concatenate"); + removeFunctionCall("__quantum__rt__string_equal"); + + removeFunctionCall("__quantum__rt__int_to_string"); + removeFunctionCall("__quantum__rt__double_to_string"); + removeFunctionCall("__quantum__rt__bool_to_string"); + removeFunctionCall("__quantum__rt__result_to_string"); + removeFunctionCall("__quantum__rt__pauli_to_string"); + removeFunctionCall("__quantum__rt__qubit_to_string"); + removeFunctionCall("__quantum__rt__range_to_string"); + removeFunctionCall("__quantum__rt__bigint_to_string"); + } + + ReplacementRulePtr RuleFactory::addRule(ReplacementRule&& rule) + { + auto ret = std::make_shared(std::move(rule)); + + rule_set_.addRule(ret); + + return ret; + } + + void RuleFactory::setDefaultIntegerWidth(uint32_t v) + { + default_integer_width_ = v; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Factory.hpp b/src/Passes/Source/Rules/Factory.hpp new file mode 100644 index 0000000000..083411cc53 --- /dev/null +++ b/src/Passes/Source/Rules/Factory.hpp @@ -0,0 +1,200 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/AllocationManager.hpp" +#include "Commandline/ConfigurationManager.hpp" +#include "QatTypes/QatTypes.hpp" +#include "Rules/FactoryConfig.hpp" +#include "Rules/ReplacementRule.hpp" +#include "Rules/RuleSet.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Rule factory provides a high-level methods to build a rule set that + /// enforces certain aspects of QIR transformation. + class RuleFactory + { + public: + /// ReplacementRule pointer type used for the construction of replacement rules + using ReplacementRulePtr = std::shared_ptr; + + /// Allocation manager pointer used to hold allocation managers + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; + + // Constructor configuration. Explicit construction with + // rule set to be configured, which can be moved using move + // semantics. No copy allowed. + // + + RuleFactory( + RuleSet& rule_set, + AllocationManagerPtr qubit_alloc_manager, + AllocationManagerPtr result_alloc_manager); + RuleFactory() = delete; + RuleFactory(RuleFactory const&) = delete; + RuleFactory(RuleFactory&&) = default; + ~RuleFactory() = default; + + // + // + + /// This takes a FactoryConfiguration as argument and enable rules accordingly. + void usingConfiguration(FactoryConfiguration const& config); + + // Generic rules + // + + /// Removes all calls to functions with a specified name. + /// This function matches on name alone and ignores function + /// arguments. + void removeFunctionCall(String const& name); + + // Conventions + // + + /// Static qubit array allocation identifies allocations, array access and releases. Each of these + /// are replaced with static values. Patterns recognised include + /// + /// ``` + /// %array = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) + /// ``` + /// + /// which is replaced by a constant pointer + /// + /// ``` + /// %array = inttoptr i64 0 to %Array* + /// ``` + /// + /// The array allocation is managed through the qubit allocation manager. Access to qubit arrays + /// + /// ``` + /// %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 7) + /// %1 = bitcast i8* %0 to %Qubit** + /// %qubit = load %Qubit*, %Qubit** %1, align 8 + /// ``` + /// + /// is replaced by off-setting the array value by 7 to get + /// + /// ``` + /// %qubit = inttoptr i64 7 to %Qubit* + /// ``` + /// + /// Finally, release is recognised and the allocation manager is invoked accordingly. + void useStaticQubitArrayAllocation(); + + /// Static qubit allocation identifies allocation and release of single qubits. It uses the qubit + /// allocation manager to track allocation and releases of qubits. It translates + /// + /// ``` + /// %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() + /// %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() + /// ``` + /// + /// to + /// + /// ``` + /// %qubit1 = inttoptr i64 0 to %Qubit* + /// %qubit2 = inttoptr i64 1 to %Qubit* + /// %qubit3 = inttoptr i64 2 to %Qubit* + /// %qubit4 = inttoptr i64 3 to %Qubit* + /// %qubit5 = inttoptr i64 4 to %Qubit* + /// ``` + /// if the BasicAllocationManager is used. + void useStaticQubitAllocation(); + + /// Static allocation of results. This feature is similar to `useStaticQubitAllocation` but uses + /// the result allocation manager. + void useStaticResultAllocation(); + + void resolveConstantArraySizes(); + + void inlineCallables(); + + // Optimisations + // + + /// Replaces branching of quantum results compared to one. This is a relatively advanced pattern, + /// intended for base profile-like constructs where + /// + /// ``` + /// %1 = tail call %Result* @__quantum__rt__result_get_one() + /// %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// is mapped into + /// + /// ``` + /// %1 = call i1 @__quantum__qis__read_result__body(%Result* %0) + /// br i1 %1, label %then0__1, label %continue__1 + /// ``` + /// + /// which removes the need for constant one. + void optimiseResultOne(); + + /// Replaces branching of quantum results compared to zero. This method is not implemented yet. + void optimiseResultZero(); + + // Disabling by feature + // + + /// This method disables reference counting for arrays, strings and results. It does so by simply + /// removing the instructions and the resulting code is expected to be executed either on a stack + /// VM or with shared pointer logic. + void disableReferenceCounting(); + + /// This method disables alias counting for arrays, strings and results. + void disableAliasCounting(); + + /// Removes string support by removing string related instructions. At the moment these include + /// `__quantum__rt__string_create`, + /// `__quantum__rt__string_update_reference_count`, `__quantum__rt__string_update_alias_count` and + /// `__quantum__rt__message`. + void disableStringSupport(); + + // Configuration + // + + /// Sets the integer width used when it cannot be deducted from the context of the transformation. + void setDefaultIntegerWidth(uint32_t v); + + private: + /// Helper function that moves a replacement rule into a shared pointer, adds it to the rule set + /// and returns a copy of it. + ReplacementRulePtr addRule(ReplacementRule&& rule); + + // Affected artefacts + // + + RuleSet& rule_set_; ///< The rule set we are building + + // Allocation managers. + // + + /// Qubit allocation manager which is used in the case of static qubit allocation. + AllocationManagerPtr qubit_alloc_manager_{nullptr}; + + /// Result allocation manager which is used in the case of static results allocation. + AllocationManagerPtr result_alloc_manager_{nullptr}; + + /// Configuration + // + + /// The default integer width. This value is used whenever the width within the context cannot be + /// inferred. + uint32_t default_integer_width_{64}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/FactoryConfig.hpp b/src/Passes/Source/Rules/FactoryConfig.hpp new file mode 100644 index 0000000000..b0a1dc41ea --- /dev/null +++ b/src/Passes/Source/Rules/FactoryConfig.hpp @@ -0,0 +1,153 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" + +namespace microsoft +{ +namespace quantum +{ + + class FactoryConfiguration + { + public: + void setup(ConfigurationManager& config) + { + config.setSectionName("Transformation rules", "Rules used to transform instruction sequences in the QIR."); + config.addParameter( + disable_reference_counting_, "disable-reference-counting", + "Disables reference counting by instruction removal."); + + config.addParameter( + disable_reference_counting_, "disable-reference-counting", + "Disables reference counting by instruction removal."); + config.addParameter( + disable_alias_counting_, "disable-alias-counting", "Disables alias counting by instruction removal."); + config.addParameter( + disable_string_support_, "disable-string-support", "Disables string support by instruction removal."); + config.addParameter( + optimise_result_one_, "optimise-result-one", + "Maps branching based on quantum measurements compared to one to base profile " + "type measurement."); + config.addParameter( + optimise_result_zero_, "optimise-result-zero", + "Maps branching based on quantum measurements compared to zero to base profile " + "type measurement."); + config.addParameter( + use_static_qubit_array_allocation_, "use-static-qubit-array-allocation", + "Maps allocation of qubit arrays to static array allocation."); + config.addParameter( + use_static_qubit_allocation_, "use-static-qubit-allocation", + "Maps qubit allocation to static allocation."); + config.addParameter( + use_static_result_allocation_, "use-static-result-allocation", + "Maps result allocation to static allocation."); + } + + static FactoryConfiguration createDisabled() + { + FactoryConfiguration ret; + ret.disable_reference_counting_ = false; + ret.disable_alias_counting_ = false; + ret.disable_string_support_ = false; + ret.optimise_result_one_ = false; + ret.optimise_result_zero_ = false; + ret.use_static_qubit_array_allocation_ = false; + ret.use_static_qubit_allocation_ = false; + ret.use_static_result_allocation_ = false; + return ret; + } + + bool disableReferenceCounting() const + { + return disable_reference_counting_; + } + + bool disableAliasCounting() const + { + return disable_alias_counting_; + } + + bool disableStringSupport() const + { + return disable_string_support_; + } + + bool optimiseResultOne() const + { + return optimise_result_one_; + } + + bool optimiseResultZero() const + { + return optimise_result_zero_; + } + + bool useStaticQubitArrayAllocation() const + { + return use_static_qubit_array_allocation_; + } + + bool useStaticQubitAllocation() const + { + return use_static_qubit_allocation_; + } + + bool useStaticResultAllocation() const + { + return use_static_result_allocation_; + } + + uint32_t defaultIntegerWidth() const + { + return default_integer_width_; + } + + bool isDisabled() const + { + return ( + disable_reference_counting_ == false && disable_alias_counting_ == false && + disable_string_support_ == false && optimise_result_one_ == false && optimise_result_zero_ == false && + use_static_qubit_array_allocation_ == false && use_static_qubit_allocation_ == false && + use_static_result_allocation_ == false); + } + + bool isDefault() const + { + FactoryConfiguration ref{}; + + return ( + disable_reference_counting_ == ref.disable_reference_counting_ && + disable_alias_counting_ == ref.disable_alias_counting_ && + disable_string_support_ == ref.disable_string_support_ && + optimise_result_one_ == ref.optimise_result_one_ && + optimise_result_zero_ == ref.optimise_result_zero_ && + use_static_qubit_array_allocation_ == ref.use_static_qubit_array_allocation_ && + use_static_qubit_allocation_ == ref.use_static_qubit_allocation_ && + use_static_result_allocation_ == ref.use_static_result_allocation_); + } + + private: + /// Factory Configuration + /// @{ + bool disable_reference_counting_{true}; + bool disable_alias_counting_{true}; + bool disable_string_support_{true}; + /// @} + + /// Optimisations + /// @{ + bool optimise_result_one_{true}; + bool optimise_result_zero_{true}; + /// @} + + bool use_static_qubit_array_allocation_{true}; + bool use_static_qubit_allocation_{true}; + bool use_static_result_allocation_{true}; + + uint32_t default_integer_width_{64}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/IOperandPrototype.cpp b/src/Passes/Source/Rules/IOperandPrototype.cpp new file mode 100644 index 0000000000..bfb4191d0b --- /dev/null +++ b/src/Passes/Source/Rules/IOperandPrototype.cpp @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" + +namespace microsoft +{ +namespace quantum +{ + + IOperandPrototype::~IOperandPrototype() = default; + bool IOperandPrototype::matchChildren(Value* value, Captures& captures) const + { + if (!children_.empty()) + { + auto user = llvm::dyn_cast(value); + + if (user == nullptr) + { + return false; + } + + if (user->getNumOperands() != children_.size()) + { + return false; + } + + uint64_t i = 0; + while (i < children_.size()) + { + auto v = user->getOperand(static_cast(i)); + if (!children_[i]->match(v, captures)) + { + return false; + } + ++i; + } + + return true; + } + + // TODO(QAT-private-issue-33): value may be other type than llvm::User. Check other relevant types + // and deal with it. + + return true; + } + + void IOperandPrototype::addChild(Child const& child) + { + children_.push_back(child); + } + + void IOperandPrototype::captureAs(std::string capture_name) + { + capture_name_ = std::move(capture_name); + } + + bool IOperandPrototype::fail(Value* /*value*/, Captures& /*captures*/) const + { + return false; + } + + bool IOperandPrototype::success(Value* value, Captures& captures) const + { + capture(value, captures); + + auto ret = matchChildren(value, captures); + if (!ret) + { + uncapture(value, captures); + } + return ret; + } + + void IOperandPrototype::capture(Value* value, Captures& captures) const + { + if (!capture_name_.empty()) + { + captures[capture_name_] = value; + } + } + + void IOperandPrototype::uncapture(Value* /*value*/, Captures& captures) const + { + if (!capture_name_.empty()) + { + auto it = captures.find(capture_name_); + if (it == captures.end()) + { + throw std::runtime_error("Previously captured name " + capture_name_ + " not found in capture list."); + } + + captures.erase(it); + } + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/IOperandPrototype.hpp b/src/Passes/Source/Rules/IOperandPrototype.hpp new file mode 100644 index 0000000000..3f02e644dd --- /dev/null +++ b/src/Passes/Source/Rules/IOperandPrototype.hpp @@ -0,0 +1,106 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// IOperandPrototype describes an IR pattern and allows matching against + /// LLVMs llvm::Value type. Each value may or may not be captured during the + /// matching process which means that they are stored in a map under a given name. + /// Capturing is enabled using `captureAs(name)` which sets the name the + /// value should be stored under. + class IOperandPrototype + { + public: + using Instruction = llvm::Instruction; + using String = std::string; + using Value = llvm::Value; + using Child = std::shared_ptr; + using Children = std::vector; + using Captures = std::unordered_map; + + // Constructors and destructors + // + + IOperandPrototype() = default; + virtual ~IOperandPrototype(); + + // Interface functions + // + + /// Interface function which determines if a given Value matches the + /// implemented pattern. It is expected that any implementation of `match` will return a call to + /// either `success()` or `fail()`. These functions will, in turn, ensure that the node is + /// captured in the capture table (and erased upon backtracking) as well as matching children. + virtual bool match(Value* value, Captures& captures) const = 0; + + /// Interface function which defines a copy operation of the underlying implementation. Note that + /// unlike normal copy operators this operation returns a shared pointer to the new copy. + virtual Child copy() const = 0; + + // Shared functionality + // + + /// Adds a child to be matched against the matches children. Children + /// are matched in order and by size. + void addChild(Child const& child); + + /// Flags that this operand should be captured. This function ensures + /// that the captured operand is given a name. The subsequent logic + /// in this class is responsible for capturing (upon match) and + /// uncapturing (upon backtrack) with specified name + void captureAs(std::string capture_name); + + protected: + // Function to indicate match success or failure. Either of these + // must be called prior to return from an implementation of + // IOperandPrototype::match. + // + + /// Function which should be called whenever a match fails. + bool fail(Value* value, Captures& captures) const; + + /// Function which should be called whenever a match is successful. + bool success(Value* value, Captures& captures) const; + + // Helper functions for the capture logic. + // + + /// Subroutine to match all children. + bool matchChildren(Value* value, Captures& captures) const; + + // Helper functions for operation + // + + /// Shallow copy of the operand to allow name change + /// of the capture + void copyPropertiesFrom(IOperandPrototype const& other) + { + capture_name_ = other.capture_name_; + children_ = other.children_; + } + + private: + /// Captures the value into the captures table if needed. + void capture(Value* value, Captures& captures) const; + + /// Removes any captures from the captures table upon backtracking + void uncapture(Value* value, Captures& captures) const; + + // Data variables for common matching functionality + // + + std::string capture_name_{""}; ///< Name to captured value. Empty means no capture. + Children children_{}; ///< Children to match against the values children. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/BasicBlock.cpp b/src/Passes/Source/Rules/Notation/BasicBlock.cpp new file mode 100644 index 0000000000..ba11c8a085 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/BasicBlock.cpp @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr basicBlock() + { + auto ret = std::make_shared(); + + return static_cast(ret); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/BitCast.cpp b/src/Passes/Source/Rules/Notation/BitCast.cpp new file mode 100644 index 0000000000..8467cac505 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/BitCast.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr bitCast(IOperandPrototypePtr const& arg) + { + auto cast_pattern = std::make_shared(); + + cast_pattern->addChild(arg); + return static_cast(cast_pattern); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Branch.cpp b/src/Passes/Source/Rules/Notation/Branch.cpp new file mode 100644 index 0000000000..97e75b8f9c --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Branch.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr branch( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2) + { + auto branch_pattern = std::make_shared(); + + branch_pattern->addChild(cond); + branch_pattern->addChild(arg1); + branch_pattern->addChild(arg2); + + return static_cast(branch_pattern); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Call.hpp b/src/Passes/Source/Rules/Notation/Call.hpp new file mode 100644 index 0000000000..b5f64b1bc2 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Call.hpp @@ -0,0 +1,64 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/// @defgroup shorthandNotation Shorthand Notation + +#include "Rules/IOperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + /// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the + /// library focuses on making it easy to express advance patterns in just a few lines and specify + /// what parts of the IR is of interest to the replacer function. An example is following pattern + /// + /// ``` + /// auto get_one = call("__quantum__rt__result_get_one"); + /// addRule( + /// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = + /// get_one), _, _), + /// replace_branch_positive}); + /// + /// ``` + /// + /// which matches IRs of the form + /// + /// ``` + /// %1 = call %Result* @__quantum__rt__result_get_one() + /// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// The pattern futher specifies that as a successful match is obtained, a table capturing + /// certain values must be created. In the above example, the table would contain three + /// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* + /// in the QIR. This allows the replacement function to easily manipulate the DAG in these + /// three places (four if you include the main captured value which is always passed to the + /// replacement function). + + /// Shorthand notation to match an instruction for a function call. + /// The resulting IOperandPrototype matches a function call with arguments + /// as specified by the arguments given. For instance, + /// + /// ``` + /// addRule({call("foo", _, _), deleteInstruction()}); + /// ``` + /// + /// matches a call to the function `foo` with exactly two arguments. + template IOperandPrototypePtr call(std::string const& name, Args... args); + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Call.hpp.orig b/src/Passes/Source/Rules/Notation/Call.hpp.orig new file mode 100644 index 0000000000..f63d462500 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Call.hpp.orig @@ -0,0 +1,73 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/// @defgroup shorthandNotation Shorthand Notation + +<<<<<<< HEAD +#include "Rules/Notation/Call.ipp" +#include "Rules/Notation/Phi.ipp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" +#include "Rules/Patterns/PhiPattern.hpp" +======= +#include "Rules/IOperandPrototype.hpp" +>>>>>>> main + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + /// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the + /// library focuses on making it easy to express advance patterns in just a few lines and specify + /// what parts of the IR is of interest to the replacer function. An example is following pattern + /// + /// ``` + /// auto get_one = call("__quantum__rt__result_get_one"); + /// addRule( + /// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = + /// get_one), _, _), + /// replace_branch_positive}); + /// + /// ``` + /// + /// which matches IRs of the form + /// + /// ``` + /// %1 = call %Result* @__quantum__rt__result_get_one() + /// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// The pattern futher specifies that as a successful match is obtained, a table capturing + /// certain values must be created. In the above example, the table would contain three + /// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* + /// in the QIR. This allows the replacement function to easily manipulate the DAG in these + /// three places (four if you include the main captured value which is always passed to the + /// replacement function). + + /// Shorthand notation to match an instruction for a function call. + /// The resulting IOperandPrototype matches a function call with arguments + /// as specified by the arguments given. For instance, + /// + /// ``` + /// addRule({call("foo", _, _), deleteInstruction()}); + /// ``` + /// + /// matches a call to the function `foo` with exactly two arguments. + template IOperandPrototypePtr call(std::string const& name, Args... args); + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Call.ipp b/src/Passes/Source/Rules/Notation/Call.ipp new file mode 100644 index 0000000000..8cefccbacc --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Call.ipp @@ -0,0 +1,38 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Llvm/Llvm.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" + +#include +#include + +namespace microsoft { +namespace quantum { +namespace notation { + +using IOperandPrototypePtr = std::shared_ptr; + +template +IOperandPrototypePtr call(std::string const &name, Args... args) +{ + IOperandPrototypePtr ret = std::make_shared(name); + std::vector arguments{args...}; + + // Adding arguments to matching + for (auto &a : arguments) + { + ret->addChild(a); + } + + // Function name is kept in the last operand + ret->addChild(std::make_shared()); + + return ret; +} + +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp new file mode 100644 index 0000000000..601daed46d --- /dev/null +++ b/src/Passes/Source/Rules/Notation/CallByNameOnly.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr callByNameOnly(std::string const& name) + { + IOperandPrototypePtr ret = std::make_shared(name); + return ret; + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Capture.cpp b/src/Passes/Source/Rules/Notation/Capture.cpp new file mode 100644 index 0000000000..2381b0c83f --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Capture.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + Capture::Capture(std::string const& name) + : name_{name} + { + } + + IOperandPrototypePtr Capture::operator=(IOperandPrototypePtr const& other) // NOLINT + { + auto ret = other->copy(); + ret->captureAs(name_); + return ret; + } + + Capture operator""_cap(char const* name, std::size_t) + { + return Capture(name); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/ConstInt.cpp b/src/Passes/Source/Rules/Notation/ConstInt.cpp new file mode 100644 index 0000000000..22802a5e79 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/ConstInt.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr constInt() + { + auto cast_pattern = std::make_shared(); + + return static_cast(cast_pattern); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/IntToPtr.cpp b/src/Passes/Source/Rules/Notation/IntToPtr.cpp new file mode 100644 index 0000000000..523d49ffef --- /dev/null +++ b/src/Passes/Source/Rules/Notation/IntToPtr.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr intToPtr(IOperandPrototypePtr const& arg) + { + auto cast_pattern = std::make_shared(); + + cast_pattern->addChild(arg); + return static_cast(cast_pattern); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Load.cpp b/src/Passes/Source/Rules/Notation/Load.cpp new file mode 100644 index 0000000000..3cde8d858e --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Load.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr load(IOperandPrototypePtr const& arg) + { + auto ret = std::make_shared(); + + ret->addChild(arg); + return static_cast(ret); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Notation.cpp b/src/Passes/Source/Rules/Notation/Notation.cpp new file mode 100644 index 0000000000..5ac8d7642d --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Notation.cpp @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + ReplacerFunction deleteInstruction() + { + return [](ReplacementRule::Builder&, ReplacementRule::Value* val, ReplacementRule::Captures&, + ReplacementRule::Replacements& replacements) { + auto type = val->getType(); + val->replaceAllUsesWith(llvm::UndefValue::get(type)); + replacements.push_back({llvm::dyn_cast(val), nullptr}); + return true; + }; + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Notation.hpp b/src/Passes/Source/Rules/Notation/Notation.hpp new file mode 100644 index 0000000000..d194577f39 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Notation.hpp @@ -0,0 +1,203 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/// @defgroup shorthandNotation Shorthand Notation + +#include "Rules/Notation/Call.hpp" +#include "Rules/Notation/Call.ipp" +#include "Rules/Notation/Phi.ipp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" +#include "Rules/Patterns/PhiPattern.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + /// Shorthand notations to make it easy and readible to create patterns. + /// + /// + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + using ReplacerFunction = std::function; + + /// Helper class to enable literals for IR patterns. The main purpose of this class + /// is to enable notation that allows one write `"name"_cap = operandGenerator()` where + /// the operand generator is a function which creates a IOperandPrototypePtr. This notation + /// means that whenever a operand is matched, the matched value is stored under "name". + class Capture + { + public: + /// Explicit creation using string name constructor. + explicit Capture(std::string const& name); + + // Note that this operator is delibrately unconventional + IOperandPrototypePtr operator=(IOperandPrototypePtr const& other); // NOLINT + + private: + std::string name_{}; ///< Name that is assigned to the IOperandPrototype + }; + + /// @addtogroup shorthandNotation + /// @{ + /// Shorthand notations are made to make it possible to match patterns in the QIR. This part of the + /// library focuses on making it easy to express advance patterns in just a few lines and specify + /// what parts of the IR is of interest to the replacer function. An example is following pattern + /// + /// ``` + /// auto get_one = call("__quantum__rt__result_get_one"); + /// addRule( + /// {branch("cond"_cap = call("__quantum__rt__result_equal", "result"_cap = _, "one"_cap = + /// get_one), _, _), + /// replace_branch_positive}); + /// + /// ``` + /// + /// which matches IRs of the form + /// + /// ``` + /// %1 = call %Result* @__quantum__rt__result_get_one() + /// %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + /// br i1 %2, label %then0__1, label %continue__1 + /// ``` + /// + /// The pattern futher specifies that as a successful match is obtained, a table capturing + /// certain values must be created. In the above example, the table would contain three + /// entries: `cond`, `result` and `one` each of which would point to a a llvm::Value* + /// in the QIR. This allows the replacement function to easily manipulate the DAG in these + /// three places (four if you include the main captured value which is always passed to the + /// replacement function). + + /// Shorthand notation to match an instruction for a function call. + /// The resulting IOperandPrototype matches a function call with arguments + /// as specified by the arguments given. For instance, + /// + /// ``` + /// addRule({call("foo", _, _), deleteInstruction()}); + /// ``` + /// + /// matches a call to the function `foo` with exactly two arguments. + template IOperandPrototypePtr call(std::string const& name, Args... args); + + /// Matches a invoke instruction + IOperandPrototypePtr unnamedInvoke(); + + /// Matches a phi node with N arguments. + template IOperandPrototypePtr phi(Args... args); + + /// Shorthand notation to match an instruction with a specified name. + /// Unlike call, this pattern matches by name only and ignore + /// the arguments. + /// + /// ``` + /// addRule({callByNameOnly("foo"), deleteInstruction()}); + /// ``` + /// + /// matches calls to the function `foo` regardless of the number of arguments. + IOperandPrototypePtr callByNameOnly(std::string const& name); + + /// Matches the llvm::BitCast instructruction. + IOperandPrototypePtr bitCast(IOperandPrototypePtr const& arg); + + /// Matches the llvm::IntToPtr instructruction. + IOperandPrototypePtr intToPtr(IOperandPrototypePtr const& arg); + + /// Matches the llvm::ConstantInt instructruction. + IOperandPrototypePtr constInt(); + + /// Matches a branch instruction given a condition and two arguments. + IOperandPrototypePtr branch( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2); + + IOperandPrototypePtr switchOp( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2); + + /// Matches a select instruction given a condition and two arguments. + IOperandPrototypePtr select( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2); + + /// Matches a load instruction with one argument. + IOperandPrototypePtr load(IOperandPrototypePtr const& arg); + + /// Matches a store instruction with a target and a value. + /// ``` + /// addRule({store("target"_cap = _, "value"_cap = _), replaceConstExpr}); + /// ``` + /// where we want to match all store instructions and do not really care about how the target or + /// value came about. In this case, we may want to capture the values to, for instance, make + /// assignment at compile time. + IOperandPrototypePtr store(IOperandPrototypePtr const& target, IOperandPrototypePtr const& value); + + /// Matches a load instruction with one argument. + IOperandPrototypePtr basicBlock(); + + /// @addtogroup shorthandNotation + /// @{ + /// The module further has shorthand notation for often encountered patterns such as any operand. + + /// Shorthand notation for a wildcard which matches anything. This value + /// is useful when for instance capturing the arguments of a function call where the + /// origin of the value does not matter to the pattern. + static std::shared_ptr const _ = std::make_shared(); // NOLINT + + /// @} + + /// @addtogroup shorthandNotation + /// @{ + /// The module also implements shorthand notation for common replacers. + + /// Shorthand notation to delete an instruction. If passed as the replacement function, this + /// function generates a replacer that deletes the instruction. This is a shorthand notation for + /// deleting an instruction that can be used with a custom rule when building a ruleset. This + /// function can be used with shorthand notation for patterns as follows: + /// ``` + /// addRule({callByNameOnly(name), deleteInstruction()}); + /// ``` + /// to delete the instructions that calls functions with the name `name`. + ReplacerFunction deleteInstruction(); + /// @} + + /// @addtogroup shorthandNotation + /// @{ + /// Literals which ease the burned of capturing values and increase readibility of the code. + + /// Literal for specifying the capture of a llvm::Value*. This literal calls the + /// IOperandPrototype::enableCapture through the assignment of a IOperandPrototypePtr to the class + /// Capture. + /// + /// As an example, one may want to match the pattern `foo(bar(baz(x)), y)` and extract the variable + /// `x` to add meta data to it. The corresponding IR could look like: + /// ``` + /// %1 = call %Type* @baz(%Type* %0) + /// %2 = call %Type* @bar(%Type* %1) + /// call void @foo(%Type* %2, %Type* %3) + /// ``` + /// To match this pattern, one would create the pattern `call("foo", call("bar", call("baz", "x"_cap + /// = _)), _)`. This pattern would ensure that at the time where the replacer function is called, + /// the value stored in `%0` is captured under the name `x`. + /// + Capture operator""_cap(char const* name, std::size_t); + /// @} + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Phi.ipp b/src/Passes/Source/Rules/Notation/Phi.ipp new file mode 100644 index 0000000000..0217b4c95a --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Phi.ipp @@ -0,0 +1,38 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Llvm/Llvm.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" +#include "Rules/Patterns/PhiPattern.hpp" +#include "Rules/ReplacementRule.hpp" + +#include +#include + +namespace microsoft { +namespace quantum { +namespace notation { + +using IOperandPrototypePtr = std::shared_ptr; + +template +IOperandPrototypePtr phi(Args... args) +{ + IOperandPrototypePtr ret = std::make_shared(); + std::vector arguments{args...}; + + // Adding arguments to matching + for (auto &a : arguments) + { + ret->addChild(a); + } + + return ret; +} + +} // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Select.cpp b/src/Passes/Source/Rules/Notation/Select.cpp new file mode 100644 index 0000000000..63b03d363c --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Select.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr select( + IOperandPrototypePtr const& cond, + IOperandPrototypePtr const& arg1, + IOperandPrototypePtr const& arg2) + { + auto select_pattern = std::make_shared(); + + select_pattern->addChild(cond); + select_pattern->addChild(arg1); + select_pattern->addChild(arg2); + + return static_cast(select_pattern); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Store.cpp b/src/Passes/Source/Rules/Notation/Store.cpp new file mode 100644 index 0000000000..e13931154b --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Store.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr store(IOperandPrototypePtr const& target, IOperandPrototypePtr const& value) + { + auto ret = std::make_shared(); + + ret->addChild(target); + ret->addChild(value); + return static_cast(ret); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/Switch.cpp b/src/Passes/Source/Rules/Notation/Switch.cpp new file mode 100644 index 0000000000..a8ce472889 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/Switch.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr switchOp( + IOperandPrototypePtr const& /*cond*/, + IOperandPrototypePtr const& /*arg1*/, + IOperandPrototypePtr const& /*arg2*/) + { + auto switch_pattern = std::make_shared(); + + // TODO(tfr): finish switch pattern + // switch_pattern->addChild(cond); + // switch_pattern->addChild(arg1); + // switch_pattern->addChild(arg2); + + return static_cast(switch_pattern); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp new file mode 100644 index 0000000000..551b1833a2 --- /dev/null +++ b/src/Passes/Source/Rules/Notation/UnnamedInvoke.cpp @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Notation/Notation.hpp" +#include "Rules/Patterns/UnnamedInvokePattern.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + namespace notation + { + + using IOperandPrototypePtr = std::shared_ptr; + + IOperandPrototypePtr unnamedInvoke() + { + auto ret = std::make_shared(); + + return static_cast(ret); + } + + } // namespace notation +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/AnyPattern.cpp b/src/Passes/Source/Rules/Patterns/AnyPattern.cpp new file mode 100644 index 0000000000..71efeb962c --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/AnyPattern.cpp @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/AnyPattern.hpp" + +namespace microsoft +{ +namespace quantum +{ + + AnyPattern::AnyPattern() = default; + AnyPattern::~AnyPattern() = default; + bool AnyPattern::match(Value* instr, Captures& captures) const + { + return success(instr, captures); + } + + AnyPattern::Child AnyPattern::copy() const + { + return std::make_shared(); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/AnyPattern.hpp b/src/Passes/Source/Rules/Patterns/AnyPattern.hpp new file mode 100644 index 0000000000..be67dcffe9 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/AnyPattern.hpp @@ -0,0 +1,36 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Pattern that matches any operand. + class AnyPattern : public IOperandPrototype + { + public: + // Constructors. + // + AnyPattern(); + ~AnyPattern() override; + + // "Any" implementation of the member functions in IOperandPrototype. + + /// Match of any operand always returns true and ignores children. + bool match(Value* instr, Captures& captures) const override; + + /// Creates a copy of the AnyPattern instance. + Child copy() const override; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/CallPattern.cpp b/src/Passes/Source/Rules/Patterns/CallPattern.cpp new file mode 100644 index 0000000000..f921e69e54 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/CallPattern.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/CallPattern.hpp" + +namespace microsoft +{ +namespace quantum +{ + + CallPattern::CallPattern(String const& name) + : name_{name} + { + } + + CallPattern::~CallPattern() = default; + + bool CallPattern::match(Value* instr, Captures& captures) const + { + auto* call_instr = llvm::dyn_cast(instr); + if (call_instr == nullptr) + { + return fail(instr, captures); + } + + auto target_function = call_instr->getCalledFunction(); + if (target_function == nullptr) + { + return fail(instr, captures); + } + + auto name = target_function->getName(); + + if (name != name_) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + CallPattern::Child CallPattern::copy() const + { + auto ret = std::make_shared(name_); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/CallPattern.hpp b/src/Passes/Source/Rules/Patterns/CallPattern.hpp new file mode 100644 index 0000000000..d25c8a7ff2 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/CallPattern.hpp @@ -0,0 +1,51 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class CallPattern : public IOperandPrototype + { + public: + using String = std::string; + + // Construction of the call pattern by name or move only. + // + + /// Construction by name. + explicit CallPattern(String const& name); + + /// Copy construction prohibited. + CallPattern(CallPattern const& other) = delete; + + /// Move construction allowed. + CallPattern(CallPattern&& other) = default; + + /// Destructor implementation. + ~CallPattern() override; + + // Call implmenetation of the member functions in IOperandPrototype. + // + + /// Matches the callee by name. + bool match(Value* instr, Captures& captures) const override; + + /// Creates a copy of itself. + Child copy() const override; + + private: + String name_{}; ///< Name of the callee to match against. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/Instruction.cpp b/src/Passes/Source/Rules/Patterns/Instruction.cpp new file mode 100644 index 0000000000..03c05a8fe4 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/Instruction.cpp @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/Instruction.hpp" + +namespace microsoft +{ +namespace quantum +{ + + bool StorePattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + StorePattern::Child StorePattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool LoadPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + LoadPattern::Child LoadPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool BitCastPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + BitCastPattern::Child BitCastPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool IntToPtrPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + IntToPtrPattern::Child IntToPtrPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool ConstIntPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + ConstIntPattern::Child ConstIntPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool BranchPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + BranchPattern::Child BranchPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool SelectPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + SelectPattern::Child SelectPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool BasicBlockPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + BasicBlockPattern::Child BasicBlockPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + + bool SwitchPattern::match(Value* instr, Captures& captures) const + { + auto* load_instr = llvm::dyn_cast(instr); + if (load_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + SwitchPattern::Child SwitchPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/Instruction.hpp b/src/Passes/Source/Rules/Patterns/Instruction.hpp new file mode 100644 index 0000000000..3d4e3ed37b --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/Instruction.hpp @@ -0,0 +1,81 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class StorePattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class LoadPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class BitCastPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class IntToPtrPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class ConstIntPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class BranchPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class SelectPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class BasicBlockPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + + class SwitchPattern : public IOperandPrototype + { + public: + bool match(Value* instr, Captures& captures) const override; + Child copy() const override; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/PhiPattern.cpp b/src/Passes/Source/Rules/Patterns/PhiPattern.cpp new file mode 100644 index 0000000000..d18f2931da --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/PhiPattern.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/PhiPattern.hpp" + +namespace microsoft +{ +namespace quantum +{ + + PhiPattern::~PhiPattern() = default; + + bool PhiPattern::match(Value* instr, Captures& captures) const + { + auto* phi_node = llvm::dyn_cast(instr); + if (phi_node == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + PhiPattern::Child PhiPattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/PhiPattern.hpp b/src/Passes/Source/Rules/Patterns/PhiPattern.hpp new file mode 100644 index 0000000000..b405204e42 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/PhiPattern.hpp @@ -0,0 +1,48 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class PhiPattern : public IOperandPrototype + { + public: + using String = std::string; + + // Construction of the call pattern by name or move only. + // + + /// Construction by name. + PhiPattern() = default; + + /// Copy construction prohibited. + PhiPattern(PhiPattern const& other) = delete; + + /// Move construction allowed. + PhiPattern(PhiPattern&& other) = default; + + /// Destructor implementation. + ~PhiPattern() override; + + // Phi implmenetation of the member functions in IOperandPrototype. + // + + /// Matches the phi node. + bool match(Value* instr, Captures& captures) const override; + + /// Creates a copy of itself. + Child copy() const override; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp new file mode 100644 index 0000000000..b517f27b64 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" +#include "Rules/Patterns/UnnamedInvokePattern.hpp" + +namespace microsoft +{ +namespace quantum +{ + + UnnamedInvokePattern::~UnnamedInvokePattern() = default; + + bool UnnamedInvokePattern::match(Value* instr, Captures& captures) const + { + auto* call_instr = llvm::dyn_cast(instr); + if (call_instr == nullptr) + { + return fail(instr, captures); + } + + return success(instr, captures); + } + + UnnamedInvokePattern::Child UnnamedInvokePattern::copy() const + { + auto ret = std::make_shared(); + ret->copyPropertiesFrom(*this); + return std::move(ret); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.hpp b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.hpp new file mode 100644 index 0000000000..05f182ca21 --- /dev/null +++ b/src/Passes/Source/Rules/Patterns/UnnamedInvokePattern.hpp @@ -0,0 +1,49 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/IOperandPrototype.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class UnnamedInvokePattern : public IOperandPrototype + { + public: + using String = std::string; + + // Construction + // + + UnnamedInvokePattern() = default; + + /// Copy construction prohibited. + UnnamedInvokePattern(UnnamedInvokePattern const& other) = delete; + + /// Move construction allowed. + UnnamedInvokePattern(UnnamedInvokePattern&& other) = default; + + /// Destructor implementation. + ~UnnamedInvokePattern() override; + + // Call implementation of the member functions in IOperandPrototype. + // + + /// Matches the callee by name. + bool match(Value* instr, Captures& captures) const override; + + /// Creates a copy of itself. + Child copy() const override; + + private: + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/ReplacementRule.cpp b/src/Passes/Source/Rules/ReplacementRule.cpp new file mode 100644 index 0000000000..fa0c11238e --- /dev/null +++ b/src/Passes/Source/Rules/ReplacementRule.cpp @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/ReplacementRule.hpp" + +namespace microsoft +{ +namespace quantum +{ + + ReplacementRule::ReplacementRule(IOperandPrototypePtr&& pattern, ReplaceFunction&& replacer) + : pattern_{std::move(pattern)} + , replacer_{std::move(replacer)} + { + } + + void ReplacementRule::setPattern(IOperandPrototypePtr&& pattern) + { + pattern_ = std::move(pattern); + } + + void ReplacementRule::setReplacer(ReplaceFunction const& replacer) + { + replacer_ = replacer; + } + + bool ReplacementRule::match(Value* value, Captures& captures) const + { + if (pattern_ == nullptr) + { + return false; + } + + return pattern_->match(value, captures); + } + + bool ReplacementRule::replace(Builder& builder, Value* value, Captures& captures, Replacements& replacements) const + { + if (replacer_) + { + auto ret = replacer_(builder, value, captures, replacements); + + // In case replacement failed, the captures are deleted. + if (!ret) + { + captures.clear(); + } + + return ret; + } + + return false; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/ReplacementRule.hpp b/src/Passes/Source/Rules/ReplacementRule.hpp new file mode 100644 index 0000000000..6a3e6ae398 --- /dev/null +++ b/src/Passes/Source/Rules/ReplacementRule.hpp @@ -0,0 +1,77 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Patterns/AnyPattern.hpp" +#include "Rules/Patterns/CallPattern.hpp" +#include "Rules/Patterns/Instruction.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Rule that describes a pattern and how to make a replacement of the matched values. + /// The class contains a OperandPrototype which is used to test whether an LLVM IR value + /// follows a specific pattern. The class also holds a function pointer to logic that + /// allows replacement of the specified value. + class ReplacementRule + { + public: + /// Table to store LLVM values using a name. + using Captures = IOperandPrototype::Captures; + + /// Value alias for shorthand usage. + using Value = llvm::Value; + + /// Pointer to the pattern type. + using IOperandPrototypePtr = std::shared_ptr; + + /// Builder alias for shorthand notation. + using Builder = llvm::IRBuilder<>; + + /// List of replacements. + using Replacements = std::vector>; + + /// Function to perform replacements. + using ReplaceFunction = std::function; + + // Constructors and destructors + // + + ReplacementRule() = default; + ReplacementRule(IOperandPrototypePtr&& pattern, ReplaceFunction&& replacer); + + // Rule configuration + // + + /// Sets the pattern describing logic to be replaced. + void setPattern(IOperandPrototypePtr&& pattern); + + /// Sets the replacer logic which given a successful match will perform + /// a replacement on the IR. + void setReplacer(ReplaceFunction const& replacer); + + // Operation + // + + /// Tests whether a given value matches the rule pattern and store captures. + /// The function returns true if the match was successful in which case captures + /// are recorded. + bool match(Value* value, Captures& captures) const; + + /// Invokes the replacer given a matched value and its corresponding captures + bool replace(Builder& builder, Value* value, Captures& captures, Replacements& replacements) const; + + private: + IOperandPrototypePtr pattern_{nullptr}; ///< Pattern to be matched against + ReplaceFunction replacer_{nullptr}; ///< Function to perform replacement upon match. + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/RuleSet.cpp b/src/Passes/Source/Rules/RuleSet.cpp new file mode 100644 index 0000000000..81d68c4fe9 --- /dev/null +++ b/src/Passes/Source/Rules/RuleSet.cpp @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/ReplacementRule.hpp" +#include "Rules/RuleSet.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +namespace microsoft +{ +namespace quantum +{ + + bool RuleSet::matchAndReplace(Instruction* value, Replacements& replacements) + { + Captures captures; + for (auto const& rule : rules_) + { + // Checking if the rule is matched and keep track of captured nodes + if (rule->match(value, captures)) + { + + // If it is matched, we attempt to replace it + llvm::IRBuilder<> builder{value}; + if (rule->replace(builder, value, captures, replacements)) + { + return true; + } + else + { + captures.clear(); + } + } + } + return false; + } + + void RuleSet::addRule(ReplacementRulePtr const& rule) + { + rules_.push_back(rule); + } + + void RuleSet::addRule(ReplacementRule&& rule) + { + addRule(std::make_shared(std::move(rule))); + } + + void RuleSet::clear() + { + rules_.clear(); + } + + uint64_t RuleSet::size() const + { + return rules_.size(); + } +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/RuleSet.hpp b/src/Passes/Source/Rules/RuleSet.hpp new file mode 100644 index 0000000000..bcdc9f8de2 --- /dev/null +++ b/src/Passes/Source/Rules/RuleSet.hpp @@ -0,0 +1,75 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/IAllocationManager.hpp" +#include "Rules/IOperandPrototype.hpp" +#include "Rules/ReplacementRule.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// RuleSet contains a set of replacement rules and the corresponding logic + /// to apply the rules. The class allows one to apply the rules by which + /// each rule is tested one-by-one until a successful attempt at performing + /// a replace has happened, or the list was exhausted. + class RuleSet + { + public: + using ReplacementRulePtr = std::shared_ptr; + using Rules = std::vector; + using Replacements = ReplacementRule::Replacements; + using Captures = IOperandPrototype::Captures; + using Instruction = llvm::Instruction; + using Value = llvm::Value; + using Builder = ReplacementRule::Builder; + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; + + // Constructors + // + RuleSet() = default; + RuleSet(RuleSet const&) = default; + RuleSet(RuleSet&&) = default; + ~RuleSet() = default; + + // Operators + // + + RuleSet& operator=(RuleSet const&) = default; + RuleSet& operator=(RuleSet&&) = default; + + // Operating rule sets + // + + /// Matches patterns and runs the replacement routines if a match + /// is found. The function returns true if a pattern is matched and + /// and the replacement was a success. In all other cases, it returns + /// false. + bool matchAndReplace(Instruction* value, Replacements& replacements); + + // Set up and configuration + // + + /// Adds a new replacement rule to the set. + void addRule(ReplacementRulePtr const& rule); + void addRule(ReplacementRule&& rule); + + /// Clears the rule set for all rules. + void clear(); + + /// Returns the size of the rule set. + uint64_t size() const; + + private: + Rules rules_; ///< Rules that describes QIR mappings + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Rules/Tests/Unit/BasicRuleSetOps.cpp b/src/Passes/Source/Rules/Tests/Unit/BasicRuleSetOps.cpp new file mode 100644 index 0000000000..48e1b0e1b8 --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/BasicRuleSetOps.cpp @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/ReplacementRule.hpp" +#include "Rules/RuleSet.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, BasicOperations) +{ + using namespace microsoft::quantum::notation; + + RuleSet rule_set; + EXPECT_EQ(rule_set.size(), 0); + auto deleter = deleteInstruction(); + + ReplacementRule rule{callByNameOnly("__quantum__rt__qubit_release_array"), std::move(deleter)}; + auto ret = std::make_shared(rule); + + rule_set.addRule(ret); + + EXPECT_EQ(rule_set.size(), 1); + rule_set.clear(); + EXPECT_EQ(rule_set.size(), 0); +} + +TEST(RuleSetTestSuite, SetReplacerAndPattern) +{ + using namespace microsoft::quantum::notation; + + auto ir_manip = newIrManip(R"script( + %qubit = inttoptr i64 0 to %Qubit* + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + ReplacementRule rule{nullptr, nullptr}; + auto ret = std::make_shared(rule); + ret->setReplacer(deleteInstruction()); + ret->setPattern(callByNameOnly("__quantum__rt__qubit_release")); + rule_set.addRule(ret); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release(%Qubit* %qubit)"}) || + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); + ir_manip->applyProfile(profile); + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release(%Qubit* null)"}) || + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); +} + +TEST(RuleSetTestSuite, NullPattern) +{ + using namespace microsoft::quantum::notation; + + auto ir_manip = newIrManip(R"script( + %qubit = inttoptr i64 0 to %Qubit* + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + ReplacementRule rule{nullptr, deleteInstruction()}; + auto ret = std::make_shared(rule); + rule_set.addRule(ret); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release(%Qubit* %qubit)"}) || + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); + ir_manip->applyProfile(profile); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release(%Qubit* null)"}) || + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); +} + +TEST(RuleSetTestSuite, NullReplacer) +{ + using namespace microsoft::quantum::notation; + + auto ir_manip = newIrManip(R"script( + %qubit = inttoptr i64 0 to %Qubit* + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + ReplacementRule rule{callByNameOnly("__quantum__rt__qubit_release"), nullptr}; + auto ret = std::make_shared(rule); + rule_set.addRule(ret); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release(%Qubit* %qubit)"}) || + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); + ir_manip->applyProfile(profile); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release(%Qubit* null)"}) || + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp b/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp new file mode 100644 index 0000000000..52901f1bee --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/BranchOnOne.cpp @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "Rules/ReplacementRule.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__reset__body(%Qubit*)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_one()"); + ir_manip->declareFunction("void @__quantum__rt__result_update_reference_count(%Result*, i32)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_one()"); + ir_manip->declareFunction("i1 @__quantum__rt__result_equal(%Result*, %Result*)"); + ir_manip->declareFunction("void @send_message()"); + ir_manip->declareFunction("void @bye_message()"); + ir_manip->declareFunction("void @__quantum__qis__mz__body(%Qubit*, %Result*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, BranchOnOne) +{ + auto ir_manip = newIrManip(R"script( + %0 = inttoptr i64 0 to %Result* + call void @__quantum__qis__mz__body(%Qubit* null, %Result* %0) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %1 = tail call %Result* @__quantum__rt__result_get_one() + %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + tail call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 + +then0__1: + tail call void @send_message() + br label %continue__1 + +continue__1: + tail call void @bye_message() + ret i8 0 + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + // factory.useStaticResultAllocation(); + + factory.optimiseResultOne(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + ir_manip->applyProfile(profile); + + // This optimistation is specific to the the __quantum__qis__read_result__body which + // returns 1 or 0 depending on the result. We expect that + // + // %1 = tail call %Result* @__quantum__rt__result_get_one() + // %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + // br i1 %2, label %then0__1, label %continue__1 + // + // will be mapped to using this instruction. + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%0 = tail call i1 @__quantum__qis__read_result__body(%Result* null)", + "br i1 %0, label %then0__1, label %continue__1"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"%2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1)"}) || + ir_manip->hasInstructionSequence({"%2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1)"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"%2 = call i1 @__quantum__rt__result_get_one()"}) || + ir_manip->hasInstructionSequence({"%2 = tail call i1 @__quantum__rt__result_get_one()"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/BranchOnZero.cpp b/src/Passes/Source/Rules/Tests/Unit/BranchOnZero.cpp new file mode 100644 index 0000000000..93ea6150f5 --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/BranchOnZero.cpp @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "Rules/ReplacementRule.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__reset__body(%Qubit*)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_zero()"); + ir_manip->declareFunction("void @__quantum__rt__result_update_reference_count(%Result*, i32)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_zero()"); + ir_manip->declareFunction("i1 @__quantum__rt__result_equal(%Result*, %Result*)"); + ir_manip->declareFunction("void @send_message()"); + ir_manip->declareFunction("void @bye_message()"); + ir_manip->declareFunction("void @__quantum__qis__mz__body(%Qubit*, %Result*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, BranchOnZero) +{ + auto ir_manip = newIrManip(R"script( + %0 = inttoptr i64 0 to %Result* + call void @__quantum__qis__mz__body(%Qubit* null, %Result* %0) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %1 = tail call %Result* @__quantum__rt__result_get_zero() + %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + tail call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 + +then0__1: + tail call void @send_message() + br label %continue__1 + +continue__1: + tail call void @bye_message() + ret i8 0 + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + // factory.useStaticResultAllocation(); + + factory.optimiseResultZero(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + ir_manip->applyProfile(profile); + + // This optimistation is specific to the the __quantum__qis__read_result__body which + // returns 1 or 0 depending on the result. We expect that + // + // %1 = tail call %Result* @__quantum__rt__result_get_zero() + // %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + // br i1 %2, label %then0__1, label %continue__1 + // + // will be mapped to using this pattern. + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%0 = tail call i1 @__quantum__qis__read_result__body(%Result* null)", + "br i1 %0, label %continue__1, label %then0__1"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"%2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1)"}) || + ir_manip->hasInstructionSequence({"%2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1)"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"%2 = call i1 @__quantum__rt__result_get_zero()"}) || + ir_manip->hasInstructionSequence({"%2 = tail call i1 @__quantum__rt__result_get_zero()"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp b/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp new file mode 100644 index 0000000000..6865772a0d --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/DisableAliasCounting.cpp @@ -0,0 +1,172 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + ir_manip->declareOpaque("String"); + ir_manip->declareOpaque("Array"); + + ir_manip->declareFunction("%Array* @__quantum__rt__array_create_1d(i32, i64)"); + ir_manip->declareFunction("%String* @__quantum__rt__string_create(i8*)"); + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + + ir_manip->declareFunction("void @__quantum__rt__array_update_alias_count(%Array*, i32)"); + ir_manip->declareFunction("void @__quantum__rt__string_update_alias_count(%String*, i32)"); + ir_manip->declareFunction("void @__quantum__rt__result_update_alias_count(%Result*, i32)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, DISABLED_DisablingArrayhAliasCounting) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) + call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 1) + call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 -1) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableAliasCounting(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + // We expect that the calls are there initially + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 1)"})); + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 -1)"})); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"%0 = tail call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2)"})); + + // We expect that the call was removed + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 1)"})); + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 -1)"})); +} + +TEST(RuleSetTestSuite, DisablingStringAliasCounting) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %String* @__quantum__rt__string_create(i8* null) + call void @__quantum__rt__string_update_alias_count(%String* %0, i32 1) + call void @__quantum__rt__string_update_alias_count(%String* %0, i32 -1) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableAliasCounting(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + // We expect that the calls are there initially + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__string_update_alias_count(%String* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_alias_count(%String* %0, i32 1)"})); + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__string_update_alias_count(%String* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_alias_count(%String* %0, i32 -1)"})); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%0 = tail call %String* @__quantum__rt__string_create(i8* null)"})); + + // We expect that the call was removed + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__string_update_alias_count(%String* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_alias_count(%String* %0, i32 1)"})); + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__string_update_alias_count(%String* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_alias_count(%String* %0, i32 -1)"})); +} + +TEST(RuleSetTestSuite, DisablingResultAliasCounting) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %Result* @__quantum__qis__m__body(%Qubit* null) + call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 1) + call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 -1) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableAliasCounting(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + // We expect that the calls are there initially + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 1)"})); + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 -1)"})); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%0 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)"})); + + // We expect that the call was removed + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 1)"})); + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_alias_count(%Result* %0, i32 -1)"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp b/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp new file mode 100644 index 0000000000..ba80dec4af --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/DisableReferenceCounting.cpp @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + ir_manip->declareOpaque("String"); + ir_manip->declareOpaque("Array"); + + ir_manip->declareFunction("%Array* @__quantum__rt__array_create_1d(i32, i64)"); + ir_manip->declareFunction("%String* @__quantum__rt__string_create(i8*)"); + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + + ir_manip->declareFunction("void @__quantum__rt__array_update_reference_count(%Array*, i32)"); + ir_manip->declareFunction("void @__quantum__rt__string_update_reference_count(%String*, i32)"); + ir_manip->declareFunction("void @__quantum__rt__result_update_reference_count(%Result*, i32)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, DISABLED_DisablingArrayhReferenceCounting) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableReferenceCounting(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + // We expect that the calls are there initially + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 1)"})); + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1)"})); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE( + ir_manip->hasInstructionSequence({"%0 = tail call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2)"})); + + // We expect that the call was removed + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 1)"})); + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1)"})); +} + +TEST(RuleSetTestSuite, DisablingStringReferenceCounting) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %String* @__quantum__rt__string_create(i8* null) + call void @__quantum__rt__string_update_reference_count(%String* %0, i32 1) + call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableReferenceCounting(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + // We expect that the calls are there initially + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__string_update_reference_count(%String* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_reference_count(%String* %0, i32 1)"})); + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1)"})); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%0 = tail call %String* @__quantum__rt__string_create(i8* null)"})); + + // We expect that the call was removed + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__string_update_reference_count(%String* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_reference_count(%String* %0, i32 1)"})); + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1)"})); +} + +TEST(RuleSetTestSuite, DisablingResultReferenceCounting) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %Result* @__quantum__qis__m__body(%Qubit* null) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 1) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableReferenceCounting(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + // We expect that the calls are there initially + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 1)"})); + EXPECT_TRUE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1)"})); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%0 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)"})); + + // We expect that the call was removed + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 1)"})); + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1)"}) || + ir_manip->hasInstructionSequence( + {"tail call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1)"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp b/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp new file mode 100644 index 0000000000..1ff0eabf57 --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/DisableStrings.cpp @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + ir_manip->declareOpaque("String"); + ir_manip->declareOpaque("Array"); + + ir_manip->declareFunction("%String* @__quantum__rt__string_create(i8*)"); + ir_manip->declareFunction("void @__quantum__rt__message(%String*)"); + ir_manip->declareFunction("void @__quantum__rt__string_update_alias_count(%String*, i32)"); + ir_manip->declareFunction("void @__quantum__rt__string_update_reference_count(%String*, i32)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +TEST(RuleSetTestSuite, DisablingStrings) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %String* @__quantum__rt__string_create(i8* null) + call void @__quantum__rt__string_update_reference_count(%String* %0, i32 1) + call void @__quantum__rt__string_update_alias_count(%String* %0, i32 1) + call void @__quantum__rt__message(%String* %0) + call void @__quantum__rt__string_update_alias_count(%String* %0, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -11) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.disableStringSupport(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + ir_manip->applyProfile(profile); + + // We expect that the call was removed + EXPECT_EQ(ir_manip->toBodyInstructions(), IrManipulationTestHelper::Strings{"ret i8 0"}); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/FactoryConfiguration.cpp b/src/Passes/Source/Rules/Tests/Unit/FactoryConfiguration.cpp new file mode 100644 index 0000000000..2f801894f6 --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/FactoryConfiguration.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/FactoryConfig.hpp" +#include "gtest/gtest.h" + +#include + +using namespace microsoft::quantum; + +// Single allocation with action and then release +TEST(RuleSetTestSuite, FactoryConfiguration) +{ + FactoryConfiguration c1 = FactoryConfiguration::createDisabled(); + EXPECT_TRUE(c1.isDisabled()); + + FactoryConfiguration c2{}; + EXPECT_TRUE(c2.isDefault()); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp b/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp new file mode 100644 index 0000000000..b6d99b3141 --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/RemoveFunctionCall.cpp @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, RemovingFunctionCall) +{ + auto ir_manip = newIrManip(R"script( + %qubit = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %qubit) + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.removeFunctionCall("__quantum__qis__h__body"); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%qubit = tail call %Qubit* @__quantum__rt__qubit_allocate()", + "tail call void @__quantum__rt__qubit_release(%Qubit* %qubit)"})); + + // We expect that the call was removed + EXPECT_FALSE(ir_manip->hasInstructionSequence({"call void @__quantum__qis__h__body(%Qubit* %qubit)"})); + EXPECT_FALSE(ir_manip->hasInstructionSequence({"tail call void @__quantum__qis__h__body(%Qubit* %qubit)"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/SelectOnOne.cpp b/src/Passes/Source/Rules/Tests/Unit/SelectOnOne.cpp new file mode 100644 index 0000000000..e8c9fb8e0d --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/SelectOnOne.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "Rules/ReplacementRule.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("void @__quantum__qis__reset__body(%Qubit*)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_one()"); + ir_manip->declareFunction("i1 @__quantum__rt__result_equal(%Result*, %Result*)"); + ir_manip->declareFunction("void @__quantum__qis__mz__body(%Qubit*, %Result*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Select on measurement result +TEST(RuleSetTestSuite, SelectOnOne) +{ + auto ir_manip = newIrManip(R"script( + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Result* nonnull inttoptr (i64 1 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + %0 = tail call %Result* @__quantum__rt__result_get_one() + %1 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 1 to %Result*), %Result* %0) + %2 = select i1 %1, i8 3, i8 4 + %3 = add i8 2, %2 + ret i8 %3 + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.optimiseResultOne(); + }; + + auto profile = std::make_shared(std::move(configure_profile)); + ir_manip->applyProfile(profile); + + // This optimisation is specific to the the __quantum__qis__read_result__body which + // returns 1 or 0 depending on the result. We expect that + // + // %1 = tail call %Result* @__quantum__rt__result_get_one() + // %2 = tail call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + // ... + // %5 = select i1 %2, %3, %4 + // + // will be mapped to using this instruction. + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%0 = tail call i1 @__quantum__qis__read_result__body(%Result* " + "nonnull inttoptr (i64 1 to %Result*))", + "%1 = select i1 %0, i8 5, i8 6"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"%1 = call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 1 " + "to %Result*), %Result* %0)"}) || + ir_manip->hasInstructionSequence({"%1 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr " + "(i64 1 to %Result*), %Result* %0)"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"%0 = call %Result* @__quantum__rt__result_get_one()"}) || + ir_manip->hasInstructionSequence({"%0 = tail call %Result* @__quantum__rt__result_get_one()"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp b/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp new file mode 100644 index 0000000000..4bf62c7bf7 --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/SingleQubitAllocation.cpp @@ -0,0 +1,233 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Qubit* @__non_standard_allocator()"); + ir_manip->declareFunction("i8* @__non_standard_int_allocator()"); + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, AllocationActionRelease) +{ + auto ir_manip = newIrManip(R"script( + %qubit = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %qubit) + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + factory.useStaticQubitAllocation(); + }; + + auto profile = std::make_shared( + std::move(configure_profile), TransformationRulesPassConfiguration::createDisabled(), + LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%qubit = inttoptr i64 0 to %Qubit*", "call void @__quantum__qis__h__body(%Qubit* %qubit)"})); +} + +// Scenario 2 - Multiple sequential allocations +TEST(RuleSetTestSuite, MultipleAllocationsNoRelease) +{ + auto ir_manip = newIrManip(R"script( + %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() + %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() + %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() + %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() + %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() + )script"); + + auto profile = std::make_shared( + [](RuleSet& rule_set) { + auto factory = + RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.useStaticQubitAllocation(); + }, + TransformationRulesPassConfiguration::createDisabled(), LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + // Checking that static allocations happened + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + "%qubit1 = inttoptr i64 0 to %Qubit*", + "%qubit2 = inttoptr i64 1 to %Qubit*", + "%qubit3 = inttoptr i64 2 to %Qubit*", + "%qubit4 = inttoptr i64 3 to %Qubit*", + "%qubit5 = inttoptr i64 4 to %Qubit*", + })); + + // Checking that dynamic allocations were removed + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit1 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit2 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit3 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit4 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit5 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); +} + +// Scenario 3 - Allocate, release - multiple times +TEST(RuleSetTestSuite, AllocateReleaseMultipleTimes) +{ + auto ir_manip = newIrManip(R"script( + %qubit1 = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__rt__qubit_release(%Qubit* %qubit1) + %qubit2 = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__rt__qubit_release(%Qubit* %qubit2) + %qubit3 = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__rt__qubit_release(%Qubit* %qubit3) + %qubit4 = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__rt__qubit_release(%Qubit* %qubit4) + %qubit5 = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__rt__qubit_release(%Qubit* %qubit4) + )script"); + + auto profile = std::make_shared( + [](RuleSet& rule_set) { + auto factory = + RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.useStaticQubitAllocation(); + }, + TransformationRulesPassConfiguration::createDisabled(), LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + "%qubit1 = inttoptr i64 0 to %Qubit*", + "%qubit2 = inttoptr i64 0 to %Qubit*", + "%qubit3 = inttoptr i64 0 to %Qubit*", + "%qubit4 = inttoptr i64 0 to %Qubit*", + "%qubit5 = inttoptr i64 0 to %Qubit*", + })); + + // Checking that dynamic allocations were removed + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit1 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit2 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit3 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit4 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%qubit5 = call %Qubit* @__quantum__rt__qubit_allocate()", + })); +} + +// Scenario 4 - Allocate, release - multiple times +TEST(RuleSetTestSuite, ErrorAllocateReleaseByName) +{ + auto ir_manip = newIrManip(R"script( + %leftMessage = call %Qubit* @__non_standard_allocator() + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + )script"); + + auto profile = std::make_shared( + [](RuleSet& rule_set) { + auto factory = + RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.useStaticQubitAllocation(); + }, + TransformationRulesPassConfiguration::createDisabled(), LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_FALSE(ir_manip->isModuleBroken()); + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%leftMessage = call %Qubit* @__non_standard_allocator()"})); +} + +TEST(RuleSetTestSuite, ErrorAllocateReleaseByNameWithNoName) +{ + auto ir_manip = newIrManip(R"script( + %0 = call %Qubit* @__non_standard_allocator() + call void @__quantum__rt__qubit_release(%Qubit* %0) + )script"); + + auto profile = std::make_shared( + [](RuleSet& rule_set) { + auto factory = + RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.useStaticQubitAllocation(); + }, + TransformationRulesPassConfiguration::createDisabled(), LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_FALSE(ir_manip->isModuleBroken()); + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%0 = call %Qubit* @__non_standard_allocator()"})); +} + +TEST(RuleSetTestSuite, ErrorReleaseWithTypeErasedAllocation) +{ + auto ir_manip = newIrManip(R"script( + %0 = call i8* @__non_standard_int_allocator() + %1 = bitcast i8* %0 to %Qubit* + call void @__quantum__rt__qubit_release(%Qubit* %1) + )script"); + + auto profile = std::make_shared( + [](RuleSet& rule_set) { + auto factory = + RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + + factory.useStaticQubitAllocation(); + }, + TransformationRulesPassConfiguration::createDisabled(), LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_FALSE(ir_manip->isModuleBroken()); + EXPECT_TRUE(ir_manip->hasInstructionSequence({"%0 = call i8* @__non_standard_int_allocator()"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp b/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp new file mode 100644 index 0000000000..5fa806caca --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/StaticQubitArrayAllocation.cpp @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Array"); + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Array* @__quantum__rt__qubit_allocate_array(i64)"); + ir_manip->declareFunction("i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release_array(%Array*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + + return ir_manip; +} + +} // namespace + +/* + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 0) + %1 = bitcast i8* %0 to i64* + store i64 1, i64* %1, align 4 +*/ + +// Single allocation with action and then release +TEST(RuleSetTestSuite, StaticQubitArrayAllocationOffsets) +{ + auto ir_manip = newIrManip(R"script( + %array1 = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) ; offset 0 + %array2 = call %Array* @__quantum__rt__qubit_allocate_array(i64 3) ; offset 2 + %array3 = call %Array* @__quantum__rt__qubit_allocate_array(i64 5) ; offset 5 + %array4 = call %Array* @__quantum__rt__qubit_allocate_array(i64 9) ; offset 10 + %array5 = call %Array* @__quantum__rt__qubit_allocate_array(i64 14) ; offset 19 + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + factory.useStaticQubitArrayAllocation(); + }; + + auto profile = std::make_shared( + std::move(configure_profile), TransformationRulesPassConfiguration::createDisabled(), + LlvmPassesConfiguration::createDisabled()); + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%array1 = inttoptr i64 0 to %Array*", "%array2 = inttoptr i64 2 to %Array*", + "%array3 = inttoptr i64 5 to %Array*", "%array4 = inttoptr i64 10 to %Array*", + "%array5 = inttoptr i64 19 to %Array*"})); +} + +TEST(RuleSetTestSuite, StaticQubitArrayAllocationGetPtr) +{ + auto ir_manip = newIrManip(R"script( + %array1 = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array1, i64 7) + %1 = bitcast i8* %0 to %Qubit** + %qubit = load %Qubit*, %Qubit** %1, align 8 + call void @__quantum__qis__h__body(%Qubit* %qubit) + call void @__quantum__rt__qubit_release_array(%Array* %array1) + )script"); + + // TODO(tfr): Possibly the "correct" way to deal with this is to + // do a more granular approach, translating __quantum__rt__array_get_element_ptr_1d + // int to a constant i8*. For discussion with team. A good example is + // + // %array1 = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) + // %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array1, i64 7) + // %1 = bitcast i8* %0 to %Qubit** + // %qubit = load %Qubit*, %Qubit** %1, align 8 + // ;;; call @__quantum__qis__h__body(%Qubit* %qubit) < Note this instruction is missing + // + // LLVM will optimise the two last instructions away even at O0 as they are not used. + // Consequently the pattern fails. + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + factory.useStaticQubitArrayAllocation(); + }; + + auto profile = std::make_shared( + std::move(configure_profile), TransformationRulesPassConfiguration::createDisabled(), + LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%array1 = inttoptr i64 0 to %Array*", "%qubit = inttoptr i64 7 to %Qubit*"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release_array(%Array* %array1)"}) || + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release_array(%Array* %array1)"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call %Array* @__quantum__rt__qubit_allocate_array(i64 10)"}) || + ir_manip->hasInstructionSequence({"tail call %Array* @__quantum__rt__qubit_allocate_array(i64 10)"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence( + {"call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array1, i64 7)"}) || + ir_manip->hasInstructionSequence( + {"tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array1, i64 7)"})); +} + +TEST(RuleSetTestSuite, StaticQubitArrayAllocationAdvanced) +{ + auto ir_manip = newIrManip(R"script( + %array1 = call %Array* @__quantum__rt__qubit_allocate_array(i64 10) + %array2 = call %Array* @__quantum__rt__qubit_allocate_array(i64 7) + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array1, i64 7) + %1 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array2, i64 3) + %2 = bitcast i8* %0 to %Qubit** + %3 = bitcast i8* %1 to %Qubit** + %qubit1 = load %Qubit*, %Qubit** %2, align 8 + %qubit2 = load %Qubit*, %Qubit** %3, align 8 + call void @__quantum__qis__h__body(%Qubit* %qubit1) + call void @__quantum__qis__h__body(%Qubit* %qubit2) + call void @__quantum__rt__qubit_release_array(%Array* %array1) + call void @__quantum__rt__qubit_release_array(%Array* %array2) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + factory.useStaticQubitArrayAllocation(); + }; + + auto profile = std::make_shared( + std::move(configure_profile), TransformationRulesPassConfiguration::createDisabled(), + LlvmPassesConfiguration::createDisabled()); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%array1 = inttoptr i64 0 to %Array*", "%qubit1 = inttoptr i64 7 to %Qubit*"})); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%array2 = inttoptr i64 10 to %Array*", "%qubit2 = inttoptr i64 13 to %Qubit*"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release_array(%Array* %array1)"}) || + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release_array(%Array* %array1)"})); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({"call void @__quantum__rt__qubit_release_array(%Array* %array2)"}) || + ir_manip->hasInstructionSequence({"tail call void @__quantum__rt__qubit_release_array(%Array* %array2)"})); +} diff --git a/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp b/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp new file mode 100644 index 0000000000..9b0222dbce --- /dev/null +++ b/src/Passes/Source/Rules/Tests/Unit/StaticResultAllocation.cpp @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + + ir_manip->declareFunction("%Qubit* @__non_standard_allocator()"); + ir_manip->declareFunction("i8* @__non_standard_int_allocator()"); + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(RuleSetTestSuite, ResultTranslatedTo) +{ + auto ir_manip = newIrManip(R"script( + %result1 = call %Result* @__quantum__qis__m__body(%Qubit* null) + %result2 = call %Result* @__quantum__qis__m__body(%Qubit* null) + %result3 = call %Result* @__quantum__qis__m__body(%Qubit* null) + %result4 = call %Result* @__quantum__qis__m__body(%Qubit* null) + %result5 = call %Result* @__quantum__qis__m__body(%Qubit* null) + )script"); + + auto configure_profile = [](RuleSet& rule_set) { + auto factory = RuleFactory(rule_set, BasicAllocationManager::createNew(), BasicAllocationManager::createNew()); + factory.useStaticResultAllocation(); + }; + + auto profile = std::make_shared( + std::move(configure_profile), TransformationRulesPassConfiguration::createDisabled(), + LlvmPassesConfiguration::createDisabled()); + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + "%result1 = inttoptr i64 0 to %Result*", + "call void @__quantum__qis__mz__body(%Qubit* null, %Result* %result1)", + "%result2 = inttoptr i64 1 to %Result*", + "call void @__quantum__qis__mz__body(%Qubit* null, %Result* %result2)", + "%result3 = inttoptr i64 2 to %Result*", + "call void @__quantum__qis__mz__body(%Qubit* null, %Result* %result3)", + "%result4 = inttoptr i64 3 to %Result*", + "call void @__quantum__qis__mz__body(%Qubit* null, %Result* %result4)", + "%result5 = inttoptr i64 4 to %Result*", + "call void @__quantum__qis__mz__body(%Qubit* null, %Result* %result5)", + + })); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({ + "%result1 = call %Result* @__quantum__qis__m__body(%Qubit* null)", + }) || + ir_manip->hasInstructionSequence({ + "%result1 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)", + })); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({ + "%result2 = call %Result* @__quantum__qis__m__body(%Qubit* null)", + }) || + ir_manip->hasInstructionSequence({ + "%result2 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)", + })); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({ + "%result3 = call %Result* @__quantum__qis__m__body(%Qubit* null)", + }) || + ir_manip->hasInstructionSequence({ + "%result3 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)", + })); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({ + "%result4 = call %Result* @__quantum__qis__m__body(%Qubit* null)", + }) || + ir_manip->hasInstructionSequence({ + "%result4 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)", + })); + + EXPECT_FALSE( + ir_manip->hasInstructionSequence({ + "%result5 = call %Result* @__quantum__qis__m__body(%Qubit* null)", + }) || + ir_manip->hasInstructionSequence({ + "%result5 = tail call %Result* @__quantum__qis__m__body(%Qubit* null)", + })); +} diff --git a/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp b/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp new file mode 100644 index 0000000000..5388ea68e1 --- /dev/null +++ b/src/Passes/Source/TestTools/IrManipulationTestHelper.cpp @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "TestTools/IrManipulationTestHelper.hpp" + +#include "Llvm/Llvm.hpp" + +namespace microsoft +{ +namespace quantum +{ + + namespace + { + inline void ltrim(std::string& str) + { + str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](uint8_t ch) { return !std::isspace(ch); })); + } + + inline void rtrim(std::string& str) + { + str.erase( + std::find_if(str.rbegin(), str.rend(), [](uint8_t ch) { return !std::isspace(ch); }).base(), str.end()); + } + + inline void trim(std::string& s) + { + ltrim(s); + rtrim(s); + } + + } // namespace + + IrManipulationTestHelper::IrManipulationTestHelper() + { + pass_builder_.registerModuleAnalyses(module_analysis_manager_); + pass_builder_.registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_.registerFunctionAnalyses(function_analysis_manager_); + pass_builder_.registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_.crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + } + + bool IrManipulationTestHelper::fromString(String const& data) + { + module_ = llvm::parseIR(llvm::MemoryBufferRef(data, "IrManipulationTestHelper"), error_, context_); + compilation_failed_ = (module_ == nullptr); + return !compilation_failed_; + } + + String IrManipulationTestHelper::toString() const + { + String str; + llvm::raw_string_ostream ostream(str); + ostream << *module_; + ostream.flush(); + return str; + } + + IrManipulationTestHelper::Strings IrManipulationTestHelper::toBodyInstructions() + { + if (isModuleBroken()) + { + return {}; + } + + String data = toString(); + Strings ret; + + auto pos = data.find("define i8 @Main() local_unnamed_addr"); + + if (pos == String::npos) + { + return {}; + } + + // Skipping entry + pos = data.find("entry:", pos); + if (pos == String::npos) + { + return {}; + } + + auto last_pos = data.find('\n', pos); + assert(last_pos != String::npos); + + auto next_pos = data.find('\n', last_pos + 1); + auto terminator = data.find('}', pos); + + while ((next_pos != String::npos) && (next_pos < terminator)) + { + auto val = data.substr(last_pos, next_pos - last_pos); + trim(val); + + if (val != "") + { + ret.emplace_back(std::move(val)); + } + + last_pos = next_pos; + next_pos = data.find('\n', last_pos + 1); + } + + return ret; + } + + bool IrManipulationTestHelper::hasInstructionSequence(Strings const& instructions) + { + auto body_instructions = toBodyInstructions(); + uint64_t i = 0; + uint64_t j = 0; + + while (i < instructions.size() && j < body_instructions.size()) + { + auto& a = instructions[i]; + auto& b = body_instructions[j]; + if (a == b) + { + ++i; + } + + ++j; + } + + if (i < instructions.size()) + { + return false; + } + + return true; + } + + void IrManipulationTestHelper::applyProfile( + GeneratorPtr const& generator, + OptimizationLevel const& optimisation_level, + bool debug) + { + auto profile = generator->newProfile("generic", optimisation_level, debug); + profile.apply(*module_); + + // Verifying that the module is valid + if (isModuleBroken()) + { + throw std::runtime_error("Module was broken after applying result"); + } + } + + void IrManipulationTestHelper::declareOpaque(String const& name) + { + opaque_declarations_.insert(name); + } + + void IrManipulationTestHelper::declareFunction(String const& declaration) + { + function_declarations_.insert(declaration); + } + + String IrManipulationTestHelper::generateScript(String const& body, String const& args) const + { + String script = R"script( +; ModuleID = 'IrManipulationTestHelper' +source_filename = "IrManipulationTestHelper.ll" + +)script"; + + // Adding opaque types + for (auto const& op : opaque_declarations_) + { + script += "%" + op + " = type opaque\n"; + } + + script += "define i8 @Main(" + args + ") local_unnamed_addr #0 {\nentry:\n"; + script += body; + script += "\n ret i8 0\n"; + script += "\n}\n\n"; + + for (auto const& op : function_declarations_) + { + script += "declare " + op + "\n"; + } + script += "\nattributes #0 = { \"InteropFriendly\" }\n"; + return script; + } + + String IrManipulationTestHelper::getErrorMessage() const + { + String str; + llvm::raw_string_ostream ostream(str); + switch (error_.getKind()) + { + case llvm::SourceMgr::DiagKind::DK_Error: + ostream << "Error at "; + break; + case llvm::SourceMgr::DiagKind::DK_Warning: + ostream << "Warning at "; + break; + case llvm::SourceMgr::DiagKind::DK_Remark: + ostream << "Remark at "; + break; + case llvm::SourceMgr::DiagKind::DK_Note: + ostream << "Note at "; + break; + } + + ostream << error_.getLineNo() << ":" << error_.getColumnNo() << ": "; + ostream << error_.getMessage() << "\n\n"; + ostream << error_.getLineContents(); + ostream.flush(); + + return str; + } + + bool IrManipulationTestHelper::fromBodyString(String const& body, String const& args) + { + auto script = generateScript(body, args); + return fromString(script); + } + + IrManipulationTestHelper::ModulePtr& IrManipulationTestHelper::module() + { + return module_; + } + + bool IrManipulationTestHelper::isModuleBroken() + { + if (compilation_failed_) + { + return compilation_failed_; + } + + llvm::VerifierAnalysis verifier; + auto result = verifier.run(*module_, module_analysis_manager_); + return result.IRBroken; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TestTools/IrManipulationTestHelper.hpp b/src/Passes/Source/TestTools/IrManipulationTestHelper.hpp new file mode 100644 index 0000000000..76e180aedf --- /dev/null +++ b/src/Passes/Source/TestTools/IrManipulationTestHelper.hpp @@ -0,0 +1,153 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/ProfileGenerator.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class IrManipulationTestHelper + { + public: + using String = std::string; + using LLVMContext = llvm::LLVMContext; + using SMDiagnostic = llvm::SMDiagnostic; + using Module = llvm::Module; + using ModulePtr = std::unique_ptr; + using Strings = std::vector; + using OptimizationLevel = llvm::PassBuilder::OptimizationLevel; + using GeneratorPtr = std::shared_ptr; + + // IrManipulationTestHelper is default constructible with no ability to move + // or copy. + // + + IrManipulationTestHelper(); + IrManipulationTestHelper(IrManipulationTestHelper const&) = delete; + IrManipulationTestHelper& operator=(IrManipulationTestHelper const&) = delete; + IrManipulationTestHelper(IrManipulationTestHelper&&) = delete; + IrManipulationTestHelper& operator=(IrManipulationTestHelper&&) = delete; + + // Output functions + // + + /// Generates a string for the IR currently held in the module. + String toString() const; + + /// Generates a list of instructions for the main function in the module. + Strings toBodyInstructions(); + + // Test functions + // + + /// Tests whether the main body contains a sequence of instructions. This function + /// ignores instructions in-between the instruction set given. + bool hasInstructionSequence(Strings const& instructions); + + /// Applies a profile to the module to allow which transforms the IR. This + /// allow us to write small profiles to test a single piece of transformation. + void applyProfile( + GeneratorPtr const& profile, + OptimizationLevel const& optimisation_level = OptimizationLevel::O0, + bool debug = false); + + // Declaration of partial or full IR + // + + /// Declares a opaque type. Only the name of the type should be supplied to + /// this function. Example usage + /// + /// ``` + /// irmanip.declareOpaque("Qubit"); + /// ``` + void declareOpaque(String const& name); + + /// Declares a function. The full signature should be supplied to + /// as the first argument. Example usage + /// + /// ``` + /// irmanip.declareOpaque("%Result* @__quantum__rt__result_get_zero()"); + /// ``` + void declareFunction(String const& declaration); + + /// Creates an LLVM module given a function body. This function makes use + /// of the inputs from IrManipulationTestHelper::declareOpaque and + /// IrManipulationTestHelper::declareFunction to construct the full + /// IR. Example usage: + /// + /// ``` + /// irmanip.fromBodyString(R"script( + /// %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + /// call void @__quantum__qis__h__body(%Qubit* %leftMessage) + /// )script"); + /// ``` + /// + /// Returns false if the IR is invalid. + bool fromBodyString(String const& body, String const& args = ""); + + /// Generates a script given the body of the main function. + String generateScript(String const& body, String const& args = "") const; + + /// Creates an LLVM module given from a fully specified IR. This function + /// ignores all inputs from IrManipulationTestHelper::declareOpaque and + /// IrManipulationTestHelper::declareFunction. + /// + /// Returns false if the IR is invalid. + bool fromString(String const& data); + + /// Gets an error message if the compilation failed. + String getErrorMessage() const; + + /// Whether or not the module is broken. + bool isModuleBroken(); + + // Acccess member functions + // + + /// Returns a reference to the module + ModulePtr& module(); + + private: + // Declarations + // + + /// Set of opaque type declarations + std::unordered_set opaque_declarations_{}; + + /// Set of function declarations + std::unordered_set function_declarations_{}; + + // Compilation state + // + + /// Whether the compilation failed. + bool compilation_failed_{false}; + + /// The LLVM error encountered. + SMDiagnostic error_; + + /// The LLVM context. + LLVMContext context_; + + /// Pointer to the module obtained from the compilation process. + ModulePtr module_; + + // Objects used to run a set of passes + // + llvm::PassBuilder pass_builder_; + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TestTools/Tests/Unit/main.cpp b/src/Passes/Source/TestTools/Tests/Unit/main.cpp new file mode 100644 index 0000000000..ce7fde429f --- /dev/null +++ b/src/Passes/Source/TestTools/Tests/Unit/main.cpp @@ -0,0 +1,247 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +using namespace microsoft::quantum; +TEST(TestToolsTestSuite, IrParitalConstruction) +{ + + IrManipulationTestHelper input; + + input.declareOpaque("Qubit"); + input.declareOpaque("Result"); + + input.declareFunction("i1 @__quantum__rt__result_equal(%Result*, %Result*)"); + input.declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + input.declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + input.declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + input.declareFunction("%Result* @__quantum__rt__result_get_zero()"); + input.declareFunction("void @__quantum__qis__mz__body(%Qubit*, %Result*)"); + + input.fromBodyString(R"script( + %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %leftMessage) + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + + %0 = call %Result* @__quantum__rt__result_get_zero() + %1 = call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 3 to %Result*), %Result* %0) + + ret i8 0 + )script"); + + if (input.isModuleBroken()) + { + llvm::outs() << input.getErrorMessage() << "\n"; + exit(-1); + } + + EXPECT_TRUE(input.hasInstructionSequence({})); + EXPECT_TRUE(input.hasInstructionSequence( + {"call void @__quantum__qis__h__body(%Qubit* %leftMessage)", + "%0 = call %Result* @__quantum__rt__result_get_zero()"})); + + EXPECT_TRUE(input.hasInstructionSequence( + {"%0 = call %Result* @__quantum__rt__result_get_zero()", + "%1 = call i1 @__quantum__rt__result_equal(%Result* nonnull " + "inttoptr (i64 3 to %Result*), %Result* %0)"})); + + EXPECT_FALSE(input.hasInstructionSequence( + {"%0 = call %Result* @__quantum__rt__result_get_zero()", + "call void @__quantum__qis__h__body(%Qubit* %leftMessage)"})); + + EXPECT_FALSE(input.hasInstructionSequence({"%0 = call %Result* @non_existant_function()"})); + EXPECT_FALSE(input.hasInstructionSequence({""})); +} + +TEST(TestToolsTestSuite, IrFullConstruction) +{ + + IrManipulationTestHelper input; + + input.fromString(R"script( +; ModuleID = 'IrManipulationTestHelper' +source_filename = "IrManipulationTestHelper.ll" + +%Qubit = type opaque +%Result = type opaque + +define i8 @Main() local_unnamed_addr { +entry: + %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %leftMessage) + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + %0 = call %Result* @__quantum__rt__result_get_zero() + %1 = call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 3 to %Result*), %Result* %0) + ret i8 0 +} + +declare void @__quantum__qis__mz__body(%Qubit*, %Result*) local_unnamed_addr + +declare %Result* @__quantum__rt__result_get_zero() local_unnamed_addr + +declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr + +declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr + + )script"); + + EXPECT_TRUE(input.hasInstructionSequence({})); + EXPECT_TRUE(input.hasInstructionSequence( + {"call void @__quantum__qis__h__body(%Qubit* %leftMessage)", + "%0 = call %Result* @__quantum__rt__result_get_zero()"})); + + EXPECT_TRUE(input.hasInstructionSequence( + {"%0 = call %Result* @__quantum__rt__result_get_zero()", + "%1 = call i1 @__quantum__rt__result_equal(%Result* nonnull " + "inttoptr (i64 3 to %Result*), %Result* %0)"})); + + EXPECT_FALSE(input.hasInstructionSequence( + {"%0 = call %Result* @__quantum__rt__result_get_zero()", + "call void @__quantum__qis__h__body(%Qubit* %leftMessage)"})); + + EXPECT_FALSE(input.hasInstructionSequence({"%0 = call %Result* @non_existant_function()"})); + EXPECT_FALSE(input.hasInstructionSequence({""})); +} + +TEST(TestToolsTestSuite, ErrorOutput) +{ + + IrManipulationTestHelper input; + + input.fromString(R"script( +; ModuleID = 'IrManipulationTestHelper' +source_filename = "IrManipulationTestHelper.ll" + +define i8 @Main() local_unnamed_addr { +entry: + %0 = call i1 @__call_to_unkown() + ret i8 0 +} + )script"); + + EXPECT_TRUE(input.isModuleBroken()); + EXPECT_TRUE( + input.getErrorMessage().find("Error at 7:15: use of undefined value '@__call_to_unkown'") != std::string::npos); +} + +TEST(TestToolsTestSuite, BrokenIRFunctions) +{ + using Strings = IrManipulationTestHelper::Strings; + + { + IrManipulationTestHelper input; + + input.fromString(R"script( +; ModuleID = 'IrManipulationTestHelper' +source_filename = "IrManipulationTestHelper.ll" + +%Qubit = type opaque +%Result = type opaque + +define i8 @Main2() local_unnamed_addr { +entry: + %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %leftMessage) + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + %0 = call %Result* @__quantum__rt__result_get_zero() + %1 = call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 3 to %Result*), %Result* %0) + ret i8 0 +} + +declare void @__quantum__qis__mz__body(%Qubit*, %Result*) local_unnamed_addr + +declare %Result* @__quantum__rt__result_get_zero() local_unnamed_addr + +declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr + +declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr + + )script"); + + EXPECT_EQ(input.toBodyInstructions(), Strings({})); + } + + { + IrManipulationTestHelper input; + + input.fromString(R"script( + ; ModuleID = 'IrManipulationTestHelper' + source_filename = "IrManipulationTestHelper.ll" + + %Qubit = type opaque + %Result = type opaque + + define i8 @Main() local_unnamed_addr { + entry2: + %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %leftMessage) + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + %0 = call %Result* @__quantum__rt__result_get_zero() + %1 = call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 3 to %Result*), + %Result* %0) ret i8 0 + } + + declare void @__quantum__qis__mz__body(%Qubit*, %Result*) local_unnamed_addr + + declare %Result* @__quantum__rt__result_get_zero() local_unnamed_addr + + declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr + + declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr + + declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr + + declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr + + )script"); + + EXPECT_EQ(input.toBodyInstructions(), Strings({})); + } + + { + IrManipulationTestHelper input; + + input.fromString(R"script( + ; ModuleID = 'IrManipulationTestHelper' + source_filename = "IrManipulationTestHelper.ll" + + %Qubit = type opaque + %Result = type opaque + + define i8 @Main() local_unnamed_addr { + entry2: + %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__unknown_function(%Qubit* %leftMessage) + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + %0 = call %Result* @__quantum__rt__result_get_zero() + %1 = call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 3 to %Result*), + %Result* %0) ret i8 0 + } + + declare void @__quantum__qis__mz__body(%Qubit*, %Result*) local_unnamed_addr + + declare %Result* @__quantum__rt__result_get_zero() local_unnamed_addr + + declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr + + declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr + + declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr + + declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr + + )script"); + + EXPECT_EQ(input.toBodyInstructions(), Strings({})); + } +} diff --git a/src/Passes/Source/TransformationRulesPass/Tests/Unit/LoopUnrolling.cpp b/src/Passes/Source/TransformationRulesPass/Tests/Unit/LoopUnrolling.cpp new file mode 100644 index 0000000000..602dee1af9 --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/Tests/Unit/LoopUnrolling.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + ir_manip->declareOpaque("Array"); + ir_manip->declareOpaque("Tuple"); + ir_manip->declareOpaque("Range"); + ir_manip->declareOpaque("Callable"); + ir_manip->declareOpaque("String"); + + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + ir_manip->declareFunction("i64 @TeleportChain__Calculate__body(i64, %Qubit*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->generateScript(script) << "\n\n"; + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(TransformationRulesPass, LoopUnroll) +{ + auto ir_manip = newIrManip(R"script( + %q = call %Qubit* @__quantum__rt__qubit_allocate() + %ret = alloca i64, align 8 + store i64 1, i64* %ret, align 4 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %i = phi i64 [ 0, %entry ], [ %4, %exiting__1 ] + %0 = icmp sle i64 %i, 5 + br i1 %0, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %1 = load i64, i64* %ret, align 4 + %2 = call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* %q) + %3 = add i64 %1, %2 + store i64 %3, i64* %ret, align 4 + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %4 = add i64 %i, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %5 = load i64, i64* %ret, align 4 + call void @__quantum__rt__qubit_release(%Qubit* %q) + )script"); + + auto profile = std::make_shared(); + + ConfigurationManager& configuration_manager = profile->configurationManager(); + configuration_manager.addConfig(); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence( + {"%0 = tail call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* null)", + "%1 = tail call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* null)", + "%2 = tail call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* null)", + "%3 = tail call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* null)", + "%4 = tail call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* null)", + "%5 = tail call i64 @TeleportChain__Calculate__body(i64 4, %Qubit* null)"})); +} diff --git a/src/Passes/Source/TransformationRulesPass/Tests/Unit/MiniTeleChain.cpp b/src/Passes/Source/TransformationRulesPass/Tests/Unit/MiniTeleChain.cpp new file mode 100644 index 0000000000..5d215083bd --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/Tests/Unit/MiniTeleChain.cpp @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + ir_manip->declareOpaque("Array"); + ir_manip->declareOpaque("Tuple"); + ir_manip->declareOpaque("Range"); + ir_manip->declareOpaque("Callable"); + ir_manip->declareOpaque("String"); + + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + ir_manip->declareFunction("%Array* @__quantum__rt__qubit_allocate_array(i64)"); + ir_manip->declareFunction("void @__quantum__rt__array_update_alias_count(%Array*, i32)"); + ir_manip->declareFunction("void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)"); + ir_manip->declareFunction("i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64)"); + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__reset__body(%Qubit*)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_one()"); + ir_manip->declareFunction("i1 @__quantum__rt__result_equal(%Result*, %Result*)"); + ir_manip->declareFunction("void @__quantum__rt__result_update_reference_count(%Result*, i32)"); + ir_manip->declareFunction("void @__quantum__qis__z__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__x__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__rt__message(%String*)"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release_array(%Array*)"); + ir_manip->declareFunction("%String* @__quantum__rt__result_to_string(%Result*)"); + ir_manip->declareFunction("void @__quantum__rt__string_update_reference_count(%String*, i32)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->generateScript(script) << "\n\n"; + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(TransformationRulesPass, TeleportChain) +{ + auto ir_manip = newIrManip(R"script( + %leftMessage.i = tail call %Qubit* @__quantum__rt__qubit_allocate() + %rightMessage.i = tail call %Qubit* @__quantum__rt__qubit_allocate() + %leftPreshared.i = tail call %Array* @__quantum__rt__qubit_allocate_array(i64 2) + tail call void @__quantum__rt__array_update_alias_count(%Array* %leftPreshared.i, i32 1) + %rightPreshared.i = tail call %Array* @__quantum__rt__qubit_allocate_array(i64 2) + tail call void @__quantum__rt__array_update_alias_count(%Array* %rightPreshared.i, i32 1) + tail call void @__quantum__qis__h__body(%Qubit* %leftMessage.i) + tail call void @__quantum__qis__cnot__body(%Qubit* %leftMessage.i, %Qubit* %rightMessage.i) + %0 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared.i, i64 0) + %1 = bitcast i8* %0 to %Qubit** + %2 = load %Qubit*, %Qubit** %1, align 8 + %3 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared.i, i64 0) + %4 = bitcast i8* %3 to %Qubit** + %5 = load %Qubit*, %Qubit** %4, align 8 + tail call void @__quantum__qis__h__body(%Qubit* %2) + tail call void @__quantum__qis__cnot__body(%Qubit* %2, %Qubit* %5) + %6 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared.i, i64 1) + %7 = bitcast i8* %6 to %Qubit** + %8 = load %Qubit*, %Qubit** %7, align 8 + %9 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared.i, i64 1) + %10 = bitcast i8* %9 to %Qubit** + %11 = load %Qubit*, %Qubit** %10, align 8 + tail call void @__quantum__qis__h__body(%Qubit* %8) + tail call void @__quantum__qis__cnot__body(%Qubit* %8, %Qubit* %11) + %12 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared.i, i64 0) + %13 = bitcast i8* %12 to %Qubit** + %14 = load %Qubit*, %Qubit** %13, align 8 + %15 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared.i, i64 0) + %16 = bitcast i8* %15 to %Qubit** + %17 = load %Qubit*, %Qubit** %16, align 8 + tail call void @__quantum__qis__cnot__body(%Qubit* %rightMessage.i, %Qubit* %14) + tail call void @__quantum__qis__h__body(%Qubit* %rightMessage.i) + %result.i.i.i.i = tail call %Result* @__quantum__qis__m__body(%Qubit* %rightMessage.i) + tail call void @__quantum__qis__reset__body(%Qubit* %rightMessage.i) + %18 = tail call %Result* @__quantum__rt__result_get_one() + %19 = tail call i1 @__quantum__rt__result_equal(%Result* %result.i.i.i.i, %Result* %18) + tail call void @__quantum__rt__result_update_reference_count(%Result* %result.i.i.i.i, i32 -1) + br i1 %19, label %then0__1.i.i.i, label %continue__1.i.i.i + +then0__1.i.i.i: ; preds = %entry + tail call void @__quantum__qis__z__body(%Qubit* %17) + br label %continue__1.i.i.i + +continue__1.i.i.i: ; preds = %then0__1.i.i.i, %entry + %result.i1.i.i.i = tail call %Result* @__quantum__qis__m__body(%Qubit* %14) + tail call void @__quantum__qis__reset__body(%Qubit* %14) + %20 = tail call %Result* @__quantum__rt__result_get_one() + %21 = tail call i1 @__quantum__rt__result_equal(%Result* %result.i1.i.i.i, %Result* %20) + tail call void @__quantum__rt__result_update_reference_count(%Result* %result.i1.i.i.i, i32 -1) + br i1 %21, label %then0__2.i.i.i, label %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + +then0__2.i.i.i: ; preds = %continue__1.i.i.i + tail call void @__quantum__qis__x__body(%Qubit* %17) + br label %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + +TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i: ; preds = %then0__2.i.i.i, %continue__1.i.i.i + %22 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared.i, i64 0) + %23 = bitcast i8* %22 to %Qubit** + %24 = load %Qubit*, %Qubit** %23, align 8 + %25 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared.i, i64 1) + %26 = bitcast i8* %25 to %Qubit** + %27 = load %Qubit*, %Qubit** %26, align 8 + %28 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared.i, i64 1) + %29 = bitcast i8* %28 to %Qubit** + %30 = load %Qubit*, %Qubit** %29, align 8 + tail call void @__quantum__qis__cnot__body(%Qubit* %24, %Qubit* %27) + tail call void @__quantum__qis__h__body(%Qubit* %24) + %result.i.i.i1.i = tail call %Result* @__quantum__qis__m__body(%Qubit* %24) + tail call void @__quantum__qis__reset__body(%Qubit* %24) + %31 = tail call %Result* @__quantum__rt__result_get_one() + %32 = tail call i1 @__quantum__rt__result_equal(%Result* %result.i.i.i1.i, %Result* %31) + tail call void @__quantum__rt__result_update_reference_count(%Result* %result.i.i.i1.i, i32 -1) + br i1 %32, label %then0__1.i.i2.i, label %continue__1.i.i4.i + +then0__1.i.i2.i: ; preds = %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + tail call void @__quantum__qis__z__body(%Qubit* %30) + br label %continue__1.i.i4.i + +continue__1.i.i4.i: ; preds = %then0__1.i.i2.i, %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + %result.i1.i.i3.i = tail call %Result* @__quantum__qis__m__body(%Qubit* %27) + tail call void @__quantum__qis__reset__body(%Qubit* %27) + %33 = tail call %Result* @__quantum__rt__result_get_one() + %34 = tail call i1 @__quantum__rt__result_equal(%Result* %result.i1.i.i3.i, %Result* %33) + tail call void @__quantum__rt__result_update_reference_count(%Result* %result.i1.i.i3.i, i32 -1) + br i1 %34, label %then0__2.i.i5.i, label %TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit + +then0__2.i.i5.i: ; preds = %continue__1.i.i4.i + tail call void @__quantum__qis__x__body(%Qubit* %30) + br label %TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit + +TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit: ; preds = %continue__1.i.i4.i, %then0__2.i.i5.i + %result.i.i = tail call %Result* @__quantum__qis__m__body(%Qubit* %leftMessage.i) + tail call void @__quantum__qis__reset__body(%Qubit* %leftMessage.i) + %35 = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared.i, i64 1) + %36 = bitcast i8* %35 to %Qubit** + %37 = load %Qubit*, %Qubit** %36, align 8 + %result.i1.i = tail call %Result* @__quantum__qis__m__body(%Qubit* %37) + tail call void @__quantum__qis__reset__body(%Qubit* %37) + tail call void @__quantum__rt__array_update_alias_count(%Array* %leftPreshared.i, i32 -1) + tail call void @__quantum__rt__array_update_alias_count(%Array* %rightPreshared.i, i32 -1) + tail call void @__quantum__rt__result_update_reference_count(%Result* %result.i.i, i32 -1) + tail call void @__quantum__rt__qubit_release(%Qubit* %leftMessage.i) + tail call void @__quantum__rt__qubit_release(%Qubit* %rightMessage.i) + tail call void @__quantum__rt__qubit_release_array(%Array* %leftPreshared.i) + tail call void @__quantum__rt__qubit_release_array(%Array* %rightPreshared.i) + %38 = tail call %String* @__quantum__rt__result_to_string(%Result* %result.i1.i) + tail call void @__quantum__rt__message(%String* %38) + tail call void @__quantum__rt__result_update_reference_count(%Result* %result.i1.i, i32 -1) + tail call void @__quantum__rt__string_update_reference_count(%String* %38, i32 -1) + )script"); + + auto profile = std::make_shared(); + + ConfigurationManager& configuration_manager = profile->configurationManager(); + configuration_manager.addConfig(); + + ir_manip->applyProfile(profile); + llvm::outs() << *ir_manip->module() << "\n"; + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + // clang-format off + "tail call void @__quantum__qis__h__body(%Qubit* null)", + "tail call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))", + "tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*))", + "tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*), %Qubit* nonnull inttoptr (i64 4 to %Qubit*))", + "tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*))", + "tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*), %Qubit* nonnull inttoptr (i64 5 to %Qubit*))", + "tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Qubit* nonnull inttoptr (i64 2 to %Qubit*))", + "tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))", + "tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Result* null)", + "tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))", + "%0 = tail call i1 @__quantum__qis__read_result__body(%Result* null)", + "br i1 %0, label %then0__1.i.i.i, label %continue__1.i.i.i", + // clang-format on + })); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + // clang-format off + "tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*), %Result* nonnull inttoptr (i64 1 to %Result*))", + "tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*))", + "%1 = tail call i1 @__quantum__qis__read_result__body(%Result* nonnull inttoptr (i64 1 to %Result*))", + "br i1 %1, label %then0__2.i.i.i, label %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i", + // clang-format on + + })); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + // clang-format off + "tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*), %Qubit* nonnull inttoptr (i64 3 to %Qubit*))", + "tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*))", + "tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*), %Result* nonnull inttoptr (i64 2 to %Result*))", + "tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*))", + "%2 = tail call i1 @__quantum__qis__read_result__body(%Result* nonnull inttoptr (i64 2 to %Result*))", + "br i1 %2, label %then0__1.i.i2.i, label %continue__1.i.i4.i", + // clang-format on + })); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + // clang-format off + "tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*), %Result* nonnull inttoptr (i64 3 to %Result*))", + "tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*))", + "%3 = tail call i1 @__quantum__qis__read_result__body(%Result* nonnull inttoptr (i64 3 to %Result*))", + "br i1 %3, label %then0__2.i.i5.i, label %TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit", + // clang-format on + })); +} diff --git a/src/Passes/Source/TransformationRulesPass/Tests/Unit/PhiElimination.cpp b/src/Passes/Source/TransformationRulesPass/Tests/Unit/PhiElimination.cpp new file mode 100644 index 0000000000..3138912d91 --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/Tests/Unit/PhiElimination.cpp @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Generators/DefaultProfileGenerator.hpp" +#include "Rules/Factory.hpp" +#include "TestTools/IrManipulationTestHelper.hpp" +#include "gtest/gtest.h" + +#include "Llvm/Llvm.hpp" + +#include + +using namespace microsoft::quantum; + +namespace +{ +using IrManipulationTestHelperPtr = std::shared_ptr; +IrManipulationTestHelperPtr newIrManip(std::string const& script) +{ + IrManipulationTestHelperPtr ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + ir_manip->declareOpaque("Result"); + ir_manip->declareOpaque("Array"); + ir_manip->declareOpaque("Tuple"); + ir_manip->declareOpaque("Range"); + ir_manip->declareOpaque("Callable"); + ir_manip->declareOpaque("String"); + + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + ir_manip->declareFunction("%Array* @__quantum__rt__qubit_allocate_array(i64)"); + ir_manip->declareFunction("void @__quantum__rt__array_update_alias_count(%Array*, i32)"); + ir_manip->declareFunction("void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)"); + ir_manip->declareFunction("i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64)"); + ir_manip->declareFunction("%Result* @__quantum__qis__m__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__reset__body(%Qubit*)"); + ir_manip->declareFunction("%Result* @__quantum__rt__result_get_one()"); + ir_manip->declareFunction("i1 @__quantum__rt__result_equal(%Result*, %Result*)"); + ir_manip->declareFunction("void @__quantum__rt__result_update_reference_count(%Result*, i32)"); + ir_manip->declareFunction("void @__quantum__qis__z__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__x__body(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__rt__message(%String*)"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release_array(%Array*)"); + ir_manip->declareFunction("%String* @__quantum__rt__result_to_string(%Result*)"); + ir_manip->declareFunction("void @__quantum__rt__string_update_reference_count(%String*, i32)"); + ir_manip->declareFunction("double @Microsoft__Quantum__Math__PI__body()"); + ir_manip->declareFunction("%Result* @Microsoft__Quantum__Qir__Emission__Iterate__body(double, double, %Qubit*)"); + ir_manip->declareFunction("void @Microsoft__Quantum__Qir__Emission__Prepare__body(%Qubit*)"); + ir_manip->declareFunction("void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit*, %Qubit*)"); + + ir_manip->declareFunction("i64 @TeleportChain__Calculate__body(i64, %Qubit*)"); + ir_manip->declareFunction("void @Microsoft__Quantum__Intrinsic__H__body(%Qubit*)"); + + if (!ir_manip->fromBodyString(script)) + { + llvm::outs() << ir_manip->generateScript(script) << "\n\n"; + llvm::outs() << ir_manip->getErrorMessage() << "\n"; + exit(-1); + } + return ir_manip; +} + +} // namespace + +// Single allocation with action and then release +TEST(TransformationRulesPass, PhiEliminationBranch1) +{ + auto ir_manip = newIrManip(R"script( + %c = inttoptr i64 0 to %Qubit* + %n = add i64 0, 1 + %q = call %Qubit* @__quantum__rt__qubit_allocate() + %ret = alloca i64, align 8 + store i64 2, i64* %ret, align 4 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %c, %Qubit* %q) + %0 = icmp ne i64 %n, 0 + br i1 %0, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + %1 = sub i64 %n, 1 + %2 = call i64 @TeleportChain__Calculate__body(i64 %1, %Qubit* %q) + %3 = add i64 %2, 2 + store i64 %3, i64* %ret, align 4 + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + %4 = load i64, i64* %ret, align 4 + call void @__quantum__rt__qubit_release(%Qubit* %q) + )script"); + + auto profile = std::make_shared(); + + ConfigurationManager& configuration_manager = profile->configurationManager(); + configuration_manager.addConfig(); + + ir_manip->applyProfile(profile); + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + "tail call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* null)", + "tail call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* null, %Qubit* null)", + "%0 = tail call i64 @TeleportChain__Calculate__body(i64 0, %Qubit* null)", + })); +} + +TEST(TransformationRulesPass, PhiEliminationBranch0) +{ + auto ir_manip = newIrManip(R"script( + %c = inttoptr i64 0 to %Qubit* + %n = add i64 0, 0 + %q = call %Qubit* @__quantum__rt__qubit_allocate() + %ret = alloca i64, align 8 + store i64 2, i64* %ret, align 4 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %c, %Qubit* %q) + %0 = icmp ne i64 %n, 0 + br i1 %0, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + %1 = sub i64 %n, 1 + %2 = call i64 @TeleportChain__Calculate__body(i64 %1, %Qubit* %q) + %3 = add i64 %2, 2 + store i64 %3, i64* %ret, align 4 + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + %4 = load i64, i64* %ret, align 4 + call void @__quantum__rt__qubit_release(%Qubit* %q) + )script"); + + auto profile = std::make_shared(); + + ConfigurationManager& configuration_manager = profile->configurationManager(); + configuration_manager.addConfig(); + + ir_manip->applyProfile(profile); + + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + "tail call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* null)", + "tail call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* null, %Qubit* null)", + })); + + EXPECT_FALSE(ir_manip->hasInstructionSequence({ + "%0 = tail call i64 @TeleportChain__Calculate__body(i64 0, %Qubit* %q)", + })); +} diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp new file mode 100644 index 0000000000..219922717c --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.cpp @@ -0,0 +1,868 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Rules/Factory.hpp" +#include "Rules/Notation/Notation.hpp" +#include "Rules/ReplacementRule.hpp" +#include "TransformationRulesPass/TransformationRulesPass.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + TransformationRulesPass::TransformationRulesPass( + RuleSet&& rule_set, + TransformationRulesPassConfiguration const& config, + Profile* profile) + : rule_set_{std::move(rule_set)} + , config_{config} + , profile_{profile} + { + } + + void TransformationRulesPass::setupCopyAndExpand() + { + using namespace microsoft::quantum::notation; + addConstExprRule( + {branch("cond"_cap = constInt(), "if_false"_cap = _, "if_true"_cap = _), + [](Builder& builder, Value* val, Captures& captures, Replacements& replacements) { + auto cst = llvm::dyn_cast(captures["cond"]); + auto instr = llvm::dyn_cast(val); + + if (cst == nullptr || instr == nullptr) + { + return false; + } + + auto type = instr->getType(); + if (type == nullptr) + { + return false; + } + + auto branch_cond = cst->getValue().getZExtValue(); + + if (branch_cond) + { + auto if_true = llvm::dyn_cast(captures["if_true"]); + + builder.CreateBr(if_true); + instr->replaceAllUsesWith(llvm::UndefValue::get(type)); + } + else + { + auto if_false = llvm::dyn_cast(captures["if_false"]); + + builder.CreateBr(if_false); + instr->replaceAllUsesWith(llvm::UndefValue::get(type)); + } + + replacements.push_back({val, nullptr}); + + return true; + }}); + + if (config_.assumeNoExceptions()) + { + // Replacing all invokes with calls + addConstExprRule({unnamedInvoke(), [](Builder& builder, Value* val, Captures&, Replacements& replacements) { + auto invoke = llvm::dyn_cast(val); + if (invoke == nullptr) + { + return false; + } + + auto callee_function = invoke->getCalledFunction(); + + // List with new call arguments + std::vector new_arguments; + for (unsigned i = 0; i < invoke->getNumArgOperands(); ++i) + { + // Getting the i'th argument + llvm::Value* arg = invoke->getArgOperand(i); + + new_arguments.push_back(arg); + } + + // Creating a new call + auto* new_call = builder.CreateCall(callee_function, new_arguments); + builder.CreateBr(invoke->getNormalDest()); + + new_call->takeName(invoke); + + // Replace all calls to old function with calls to new function + invoke->replaceAllUsesWith(new_call); + replacements.push_back({invoke, nullptr}); + return true; + }}); + } + } + + void TransformationRulesPass::addConstExprRule(ReplacementRule&& rule) + { + auto ret = std::make_shared(std::move(rule)); + + const_expr_replacements_.addRule(ret); + } + + void TransformationRulesPass::constantFoldFunction(llvm::Function& fnc) + { + std::vector to_delete; + + // Folding all constants + for (auto& basic_block : fnc) + { + + for (auto& instr : basic_block) + { + auto module = instr.getModule(); + auto const& dl = module->getDataLayout(); + auto cst = llvm::ConstantFoldInstruction(&instr, dl, nullptr); + if (cst != nullptr) + { + instr.replaceAllUsesWith(cst); + to_delete.push_back(&instr); + } + } + } + + // Deleting constants + for (auto& x : to_delete) + { + x->eraseFromParent(); + } + + // Folding constant expressions + Replacements replacements; + for (auto& basic_block : fnc) + { + for (auto& instr : basic_block) + { + + const_expr_replacements_.matchAndReplace(&instr, replacements); + } + } + + for (auto& r : replacements) + { + if (r.second != nullptr) + { + throw std::runtime_error("Real replacements not implemented."); + } + auto instr = llvm::dyn_cast(r.first); + if (instr != nullptr) + { + instr->eraseFromParent(); + continue; + } + + auto block = llvm::dyn_cast(r.first); + if (block != nullptr) + { + llvm::DeleteDeadBlock(block); + } + } + } + + llvm::Value* TransformationRulesPass::copyAndExpand( + llvm::Value* input, + DeletableInstructions& schedule_instruction_deletion) + { + llvm::Value* ret = input; + auto* call_instr = llvm::dyn_cast(input); + auto instr_ptr = llvm::dyn_cast(input); + if (call_instr != nullptr && instr_ptr != nullptr) + { + auto& instr = *instr_ptr; + + auto callee_function = call_instr->getCalledFunction(); + if (callee_function != nullptr && !callee_function->isDeclaration()) + { + ConstantArguments argument_constants{}; + std::vector remaining_arguments{}; + + uint32_t idx = 0; + auto n = static_cast(callee_function->arg_size()); + + // Finding argument constants + while (idx < n) + { + auto arg = callee_function->getArg(idx); + auto value = call_instr->getArgOperand(idx); + + auto cst = llvm::dyn_cast(value); + if (cst != nullptr) + { + argument_constants[arg->getName().str()] = cst; + } + else + { + remaining_arguments.push_back(idx); + } + + ++idx; + } + + // Making a function copy + auto new_callee = expandFunctionCall(*callee_function, argument_constants); + + // Replacing call if a new function was created + if (new_callee != nullptr) + { + + llvm::IRBuilder<> builder(call_instr); + + // List with new call arguments + std::vector new_arguments; + for (auto const& i : remaining_arguments) + { + // Getting the i'th argument + llvm::Value* arg = call_instr->getArgOperand(i); + + // Adding arguments that were not constant + if (argument_constants.find(arg->getName().str()) == argument_constants.end()) + { + new_arguments.push_back(arg); + } + } + + // Creating a new call + auto* new_call = builder.CreateCall(new_callee, new_arguments); + new_call->takeName(call_instr); + new_call->setTailCall(call_instr->isTailCall()); + new_call->setTailCallKind(call_instr->getTailCallKind()); + if (call_instr->canReturnTwice()) + { + new_call->setCanReturnTwice(); + } + + new_call->setCallingConv(call_instr->getCallingConv()); + new_call->setAttributes(call_instr->getAttributes()); + + // Replace all calls to old function with calls to new function + instr.replaceAllUsesWith(new_call); + + // Deleting instruction + schedule_instruction_deletion.push_back(&instr); + + // Folding constants in the new function as we may have replaced some of + // the arguments with constants + constantFoldFunction(*new_callee); + + // Recursion: Returning the new call as the instruction to be analysed + ret = new_call; + } + + // Deleting the function the original function if it is no longer in use + if (callee_function->use_empty()) + { + callee_function->eraseFromParent(); + } + } + } + + return ret; + } + + llvm::Value* TransformationRulesPass::detectActiveCode(llvm::Value* input, DeletableInstructions&) + { + active_pieces_.insert(input); + return input; + } + + bool TransformationRulesPass::runOnFunction(llvm::Function& function, InstructionModifier const& modifier) + { + if (function.isDeclaration()) + { + return false; + } + + if (depth_ >= config_.maxRecursion()) + { + llvm::outs() << "Exceed max recursion of " << config_.maxRecursion() << "\n"; + return false; + } + ++depth_; + + // Keep track of instructions scheduled for deletion + DeletableInstructions schedule_instruction_deletion; + + // Block queue + std::deque queue; + std::unordered_set blocks_queued; + queue.push_back(&function.getEntryBlock()); + blocks_queued.insert(&function.getEntryBlock()); + + // Executing the modifier on the function itsel + modifier(&function, schedule_instruction_deletion); + + while (!queue.empty()) + { + auto& basic_block = *(queue.front()); + queue.pop_front(); + + // Executing the modifier on the block + modifier(&basic_block, schedule_instruction_deletion); + + for (auto& instr : basic_block) + { + // Modifying instruction as needed + auto instr_ptr = modifier(&instr, schedule_instruction_deletion); + + // In case the instruction was scheduled for deletion + if (instr_ptr == nullptr) + { + continue; + } + + // Checking if we are calling a function + auto call_instr = llvm::dyn_cast(instr_ptr); + if (call_instr != nullptr) + { + auto callee_function = call_instr->getCalledFunction(); + if (callee_function != nullptr && !callee_function->isDeclaration()) + { + runOnFunction(*callee_function, modifier); + } + } + + // Following the branches to their basic blocks + auto* br_instr = llvm::dyn_cast(&instr); + if (br_instr != nullptr) + { + for (uint32_t i = 0; i < br_instr->getNumOperands(); ++i) + { + // TODO(tfr): This may not work on multi path branches (conditional) + // as we may accidentally add the final path (contains qubit release) + // and we cannot make assumptions since optimisation may have rearranged + // everything. In this case, we should revert to the order they appear in the + // function + auto bb = llvm::dyn_cast(br_instr->getOperand(i)); + if (bb != nullptr) + { + + // Ensuring that we are not scheduling the same block twice + if (blocks_queued.find(bb) == blocks_queued.end()) + { + queue.push_back(bb); + blocks_queued.insert(bb); + } + } + } + continue; + } + + // Follow the branches of + auto* switch_instr = llvm::dyn_cast(&instr); + if (switch_instr != nullptr) + { + for (uint64_t i = 0; i < switch_instr->getNumSuccessors(); ++i) + { + auto bb = switch_instr->getSuccessor(static_cast(i)); + // Ensuring that we are not scheduling the same block twice + if (blocks_queued.find(bb) == blocks_queued.end()) + { + queue.push_back(bb); + blocks_queued.insert(bb); + } + } + continue; + } + + // Checking if this is an invoke call + auto* invoke_inst = llvm::dyn_cast(&instr); + if (invoke_inst != nullptr) + { + // Checking that configuration is correct + if (!config_.assumeNoExceptions()) + { + // TODO(tfr): Unify error reporting + throw std::runtime_error("Exceptions paths cannot be handled at compile time. Either disable " + "transform-execution-path-only or add assumption assume-no-except"); + } + + // Adding the block which is the on the "no except" path + auto bb = invoke_inst->getNormalDest(); + if (blocks_queued.find(bb) == blocks_queued.end()) + { + queue.push_back(bb); + blocks_queued.insert(bb); + } + } + } + } + + // Deleting constants + for (auto& x : schedule_instruction_deletion) + { + x->eraseFromParent(); + } + + --depth_; + + return true; + } + + bool TransformationRulesPass::isActive(llvm::Value* value) const + { + return active_pieces_.find(value) != active_pieces_.end(); + } + + void TransformationRulesPass::runCopyAndExpand(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + replacements_.clear(); + // For every instruction in every block, we attempt a match + // and replace. + for (auto& function : module) + { + if (function.hasFnAttribute(config_.entryPointAttr())) + { + runOnFunction(function, [this](llvm::Value* value, DeletableInstructions& modifier) { + return copyAndExpand(value, modifier); + }); + } + } + + // Active code detection + for (auto& global : module.globals()) + { + active_pieces_.insert(&global); + for (auto& op : global.operands()) + { + active_pieces_.insert(op); + } + } + + for (auto& function : module) + { + bool is_active = false; + + // Checking if the function is referenced by a global variable + for (auto user : function.users()) + { + // If the user is active, then it should be expected that the function is also active + if (isActive(user)) + { + is_active = true; + break; + } + } + + if (is_active || function.hasFnAttribute(config_.entryPointAttr())) + { + // Marking function as active + active_pieces_.insert(&function); + + // Detecting active code + runOnFunction(function, [this](llvm::Value* value, DeletableInstructions& modifier) { + return detectActiveCode(value, modifier); + }); + } + } + + processReplacements(); + } + + void TransformationRulesPass::processReplacements() + { + // Applying all replacements + + std::unordered_set already_removed; + for (auto it = replacements_.rbegin(); it != replacements_.rend(); ++it) + { + auto instr1 = llvm::dyn_cast(it->first); + + if (instr1 == nullptr) + { + llvm::outs() << "; WARNING: cannot deal with non-instruction replacements\n"; + continue; + } + + // Checking if by accident the same instruction was added + if (already_removed.find(instr1) != already_removed.end()) + { + throw std::runtime_error("Instruction was already removed."); + } + already_removed.insert(instr1); + + // Cheking if have a replacement for the instruction + if (it->second != nullptr) + { + // ... if so, we just replace it, + auto instr2 = llvm::dyn_cast(it->second); + if (instr2 == nullptr) + { + llvm::outs() << "; WARNING: cannot replace instruction with non-instruction\n"; + continue; + } + llvm::ReplaceInstWithInst(instr1, instr2); + } + else + { + // ... otherwise we delete the the instruction + // Removing all uses + if (!instr1->use_empty()) + { + auto type = instr1->getType(); + if (type != nullptr) + { + instr1->replaceAllUsesWith(llvm::UndefValue::get(type)); + } + } + + // And finally we delete the instruction. The if statement + // is first and foremost a precaution which prevents the program + // from seg-faulting in the unlikely case that instr1->getType() is null. + if (instr1->use_empty()) + { + instr1->eraseFromParent(); + } + } + } + + replacements_.clear(); + } + + void TransformationRulesPass::runDetectActiveCode(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + blocks_to_delete_.clear(); + functions_to_delete_.clear(); + + for (auto& function : module) + { + if (isActive(&function)) + { + for (auto& block : function) + { + if (!isActive(&block)) + { + blocks_to_delete_.push_back(&block); + } + } + } + else if (!function.isDeclaration()) + { + functions_to_delete_.push_back(&function); + } + } + } + + void TransformationRulesPass::runDeleteDeadCode(llvm::Module&, llvm::ModuleAnalysisManager&) + { + + // Removing all function references and scheduling blocks for deletion + for (auto& function : functions_to_delete_) + { + // Schedule for deletion + function->replaceAllUsesWith(llvm::UndefValue::get(function->getType())); + + function->clearGC(); + function->clearMetadata(); + + // Deleteing blocks in reverse order + std::vector blocks; + for (auto& block : *function) + { + blocks.push_back(&block); + } + + // Removing backwards to avoid segfault + for (auto it = blocks.rbegin(); it != blocks.rend(); ++it) + { + auto& block = **it; + // Deleting instructions in reverse order (needed because it is a DAG structure) + std::vector instructions; + for (auto& instr : block) + { + instructions.push_back(&instr); + } + + // Removing all instructions + for (auto it2 = instructions.rbegin(); it2 != instructions.rend(); ++it2) + { + auto& instr = **it2; + instr.replaceAllUsesWith(llvm::UndefValue::get(instr.getType())); + instr.eraseFromParent(); + } + + // Removing all block references + block.replaceAllUsesWith(llvm::UndefValue::get(block.getType())); + + // Scheduling block deletion + blocks_to_delete_.push_back(&block); + } + } + + // Deleting all blocks + for (auto block : blocks_to_delete_) + { + if (block->use_empty()) + { + block->eraseFromParent(); + } + else + { + llvm::errs() << "; INTERNAL ERROR: block was supposed to be unused.\n"; + for (auto& x : block->uses()) + { + llvm::errs() << " -x " << *x << "\n"; + } + for (auto x : block->users()) + { + llvm::errs() << " -: " << *x << "\n"; + } + llvm::errs() << " ----- \n"; + llvm::errs() << *block << "\n"; + } + } + + // Removing functions + for (auto& function : functions_to_delete_) + { + if (function->isDeclaration() && function->use_empty()) + { + function->eraseFromParent(); + } + } + } + + void TransformationRulesPass::runReplacePhi(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + using namespace microsoft::quantum::notation; + auto rule = phi("b1"_cap = _, "b2"_cap = _); + IOperandPrototype::Captures captures; + std::vector to_delete; + + std::unordered_map replacements; + + for (auto& function : module) + { + for (auto& block : function) + { + std::vector instrs; + + for (auto& instr : block) + { + + if (rule->match(&instr, captures)) + { + auto phi = llvm::dyn_cast(&instr); + if (phi == nullptr) + { + continue; + } + + auto val1 = captures["b1"]; + auto val2 = captures["b2"]; + + auto block1 = phi->getIncomingBlock(0); // TODO(tfr): Make sure that block1 matches val1 + auto block2 = phi->getIncomingBlock(1); + + if (!isActive(block1)) + { + val2->takeName(&instr); + + replacements[&instr] = val2; + + to_delete.push_back(&instr); + } + else if (!isActive(block2)) + { + val1->takeName(&instr); + + replacements[&instr] = val2; + to_delete.push_back(&instr); + } + + captures.clear(); + } + } + } + } + + for (auto& r : replacements) + { + r.first->replaceAllUsesWith(r.second); + } + + for (auto& x : to_delete) + { + x->eraseFromParent(); + } + } + + void TransformationRulesPass::runApplyRules(llvm::Module& module, llvm::ModuleAnalysisManager&) + { + + replacements_.clear(); + + std::unordered_set already_visited; + for (auto& function : module) + { + if (function.hasFnAttribute(config_.entryPointAttr())) + { + runOnFunction(function, [this, &already_visited](llvm::Value* value, DeletableInstructions&) { + auto instr = llvm::dyn_cast(value); + + // Sanity check + if (already_visited.find(value) != already_visited.end()) + { + throw std::runtime_error("Already visited"); + } + already_visited.insert(value); + + // Checking if we should analyse + if (instr != nullptr) + { + rule_set_.matchAndReplace(instr, replacements_); + } + return value; + }); + + if (config_.shouldAnnotateQubitUse()) + { + std::stringstream ss{""}; + ss << profile_->getQubitAllocationManager()->maxAllocationsUsed(); + function.addFnAttr("requiredQubits", ss.str()); + } + + if (config_.shouldAnnotateResultUse()) + { + std::stringstream ss{""}; + ss << profile_->getResultAllocationManager()->maxAllocationsUsed(); + function.addFnAttr("requiredResults", ss.str()); + } + } + } + + processReplacements(); + } + + llvm::PreservedAnalyses TransformationRulesPass::run(llvm::Module& module, llvm::ModuleAnalysisManager& mam) + { + // In case the module is istructed to clone functions, + if (config_.shouldCloneFunctions()) + { + setupCopyAndExpand(); + runCopyAndExpand(module, mam); + } + + // Deleting dead code if configured to do so. This process consists + // of three steps: detecting dead code, removing phi nodes (and references) + // and finally deleting the code. This implementation is aggressive in the sense + // that any code that we cannot prove to be active is considered dead. + if (config_.shouldDeleteDeadCode()) + { + runDetectActiveCode(module, mam); + runReplacePhi(module, mam); + runDeleteDeadCode(module, mam); + } + + // Applying rule set + if (config_.shouldTransformExecutionPathOnly()) + { + // We only apply transformation rules to code which is reachable + // via the execution path. + runApplyRules(module, mam); + } + else + { + + // Otherwise we apply to all sections of the code. + replacements_.clear(); + for (auto& function : module) + { + for (auto& block : function) + { + for (auto& instr : block) + { + rule_set_.matchAndReplace(&instr, replacements_); + } + } + } + + processReplacements(); + } + + return llvm::PreservedAnalyses::none(); + } + + llvm::Function* TransformationRulesPass::expandFunctionCall( + llvm::Function& callee, + ConstantArguments const& const_args) + { + auto module = callee.getParent(); + auto& context = module->getContext(); + llvm::IRBuilder<> builder(context); + + // Copying the original function + llvm::ValueToValueMapTy remapper; + std::vector arg_types; + + // The user might be deleting arguments to the function by specifying them in + // the VMap. If so, we need to not add the arguments to the arg ty vector + // + for (auto const& arg : callee.args()) + { + // Skipping constant arguments + + if (const_args.find(arg.getName().str()) != const_args.end()) + { + continue; + } + + arg_types.push_back(arg.getType()); + } + + // Creating a new function + llvm::FunctionType* function_type = llvm::FunctionType::get( + callee.getFunctionType()->getReturnType(), arg_types, callee.getFunctionType()->isVarArg()); + auto function = llvm::Function::Create( + function_type, callee.getLinkage(), callee.getAddressSpace(), callee.getName(), module); + + // Copying the non-const arguments + auto dest_args_it = function->arg_begin(); + + for (auto const& arg : callee.args()) + { + auto const_it = const_args.find(arg.getName().str()); + if (const_it == const_args.end()) + { + // Mapping remaining function arguments + dest_args_it->setName(arg.getName()); + remapper[&arg] = &*dest_args_it++; + } + else + { + remapper[&arg] = llvm::ConstantInt::get(context, const_it->second->getValue()); + } + } + + llvm::SmallVector returns; // Ignore returns cloned. + + // Note: In LLVM 13 upgrade 'true' to 'llvm::CloneFunctionChangeType::LocalChangesOnly' + llvm::CloneFunctionInto(function, &callee, remapper, true, returns, "", nullptr); + + verifyFunction(*function); + + return function; + } + + void TransformationRulesPass::setLogger(ILoggerPtr logger) + { + logger_ = std::move(logger); + } + + bool TransformationRulesPass::isRequired() + { + return true; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp new file mode 100644 index 0000000000..3c003d011f --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPass.hpp @@ -0,0 +1,233 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" +#include "Profile/Profile.hpp" +#include "QatTypes/QatTypes.hpp" +#include "Rules/RuleSet.hpp" +#include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + /// This class applies a set of transformation rules to the IR to transform it into a new IR. The + /// rules are added using the RuleSet class which allows the developer to create one or more rules + /// on how to transform the IR. + /// + /// + /// The module executes the following steps: + /// ┌─────────────────┐ + /// │ Apply profile │ + /// └─────────────────┘ + /// │ ┌───────────────────────────────┐ + /// ├───────────────▶│ Copy and expand functions │──┐ + /// │ clone └───────────────────────────────┘ │ + /// │ functions? │ delete dead │ + /// │ ▼ code? │ + /// │ ┌───────────────────────────────┐ │ + /// ├───────────────▶│ Determine active code │ │ + /// │ delete dead └───────────────────────────────┘ │ + /// │ code? │ │ leave dead + /// │ ▼ │ code? + /// │ ┌───────────────────────────────┐ │ + /// │ │ Simplify phi nodes │ │ + /// │ └───────────────────────────────┘ │ + /// │ │ │ + /// │ ▼ │ + /// │ ┌───────────────────────────────┐ │ + /// │ │ Delete dead code │ │ + /// │ └───────────────────────────────┘ │ + /// │ │ │ + /// │ ▼ │ + /// │ fallback ┌───────────────────────────────┐ │ + /// └───────────────▶│ Apply rules │◀─┘ + /// └───────────────────────────────┘ + /// + /// Copying and expanding functions identifies function calls and identifies compile time constants + /// passed to the function. It then copies the full implementation of the function, replacing all + /// compile-time constants (and hence changing the function signature). That is, if a function call + /// `f(x, 9)` is identified, it is replaced with `f.1(x)` where `f.1` is a copy of `f` with second + /// argument written into the function. + /// + class TransformationRulesPass : public llvm::PassInfoMixin + { + public: + using Replacements = ReplacementRule::Replacements; + using Instruction = llvm::Instruction; + using Rules = std::vector; + using Value = llvm::Value; + using Builder = ReplacementRule::Builder; + using AllocationManagerPtr = IAllocationManager::AllocationManagerPtr; + using Captures = RuleSet::Captures; + using ConstantArguments = std::unordered_map; + using ILoggerPtr = std::shared_ptr; + + // Construction and destruction configuration. + // + + /// Custom default constructor + TransformationRulesPass( + RuleSet&& rule_set, + TransformationRulesPassConfiguration const& config, + Profile* profile); + + /// Copy construction is banned. + TransformationRulesPass(TransformationRulesPass const&) = delete; + + /// We allow move semantics. + TransformationRulesPass(TransformationRulesPass&&) = default; + + /// Default destruction. + ~TransformationRulesPass() = default; + + // Operators + // + + /// Copy assignment is banned. + TransformationRulesPass& operator=(TransformationRulesPass const&) = delete; + + /// Move assignment is permitted. + TransformationRulesPass& operator=(TransformationRulesPass&&) = default; + + /// Implements the transformation analysis which uses the supplied ruleset to make substitutions + /// in each function. + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + + using DeletableInstructions = std::vector; + using InstructionModifier = std::function; + + // Generic helper functions + // + + /// Generic function to apply a instructionModifier (lambda function) to every instruction in the + /// function `function`. This method follows the execution path to the extend possible and deals + /// with branching if the branch statement can be evaluated at compile time. + bool runOnFunction(llvm::Function& function, InstructionModifier const& modifier); + + /// Applies each of the replacements in the `replacements_` variable. + void processReplacements(); + + // Copy and expand + // + + /// Configuration function for copy and expand to setup the necessary rules. + void setupCopyAndExpand(); + + /// Main function for running the copy and expand functionality. This function first identifies + /// the entry point and then follows every execution path to copy the callee function for every + /// call instruction encountered. This makes that every call in the code has its own unique callee + /// function which ensures that when allocating qubits or results, the assigned registers are not + /// accidentally reused. + void runCopyAndExpand(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + + /// Test whether the instruction is a call instruction and copy the callee in case it is. This + /// function collects instructions which are scheduled for deletion at a later point. + llvm::Value* copyAndExpand(llvm::Value* input, DeletableInstructions&); + + /// Copies the function body and replace function arguments whenever arguments are constant. + llvm::Function* expandFunctionCall(llvm::Function& callee, ConstantArguments const& const_args = {}); + + /// Folds all constant expression in function. + void constantFoldFunction(llvm::Function& callee); + + /// Helper function to create replacements for constant expressions. + void addConstExprRule(ReplacementRule&& rule); + + // Dead code detection + // + void runDetectActiveCode(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + void runDeleteDeadCode(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + llvm::Value* detectActiveCode(llvm::Value* input, DeletableInstructions&); + llvm::Value* deleteDeadCode(llvm::Value* input, DeletableInstructions&); + bool isActive(llvm::Value* value) const; + + void followUsers(llvm::Value* value); + + // Phi replacement + // + + /// Function which replaces phi nodes which refer to inactive blocks. That is, in cases where + /// branch statement evaluates at compile time, only one block will be marked as active. For those + /// case we can eliminate the phi nodes. In the case where branch statements cannot be evaluated + /// all are marked as active. In this case, phi nodes are left unchanged. + void runReplacePhi(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + + // Rules + // + + void runApplyRules(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + bool onQubitRelease(llvm::Instruction* instruction, Captures& captures); + bool onQubitAllocate(llvm::Instruction* instruction, Captures& captures); + + /// Whether or not this pass is required to run. + static bool isRequired(); + + // Logger + // + void setLogger(ILoggerPtr logger); + + private: + // Pass configuration + // + + /// Rule set which describes a set of transformations to apply to the QIR. + RuleSet rule_set_{}; + + /// Configuration with enabled or disabled features, recursion limits etc. + TransformationRulesPassConfiguration config_{}; + + // Logging and data collection + // + + /// Logger which is used to collect information, debug info, warnings, errors and internal errors. + ILoggerPtr logger_{nullptr}; + + // Execution path unrolling + // + + /// Current recursion depth which is used to prevent unbound (at compile time) recursion. + uint64_t depth_{0}; + + // Copy and expand + // + + /// Rule set which is used to collapse compile-time constant expressions. + RuleSet const_expr_replacements_{}; + + // Dead code elimination + // + + /// Set to track active Values in the code. + std::unordered_set active_pieces_{}; + + /// Vector with block pointers to delete + std::vector blocks_to_delete_{}; + + /// Vector of function pointers to delete + std::vector functions_to_delete_{}; + + // Phi detection + // + + /// Registered replacements to be executed. + Replacements replacements_; + + // Profile + // + + /// Pointer to the current profile. This pointer is used to annotate top level functions with + /// regards to how many qubits they require. TODO(tfr): Consider moving into its own component. + Profile* profile_{nullptr}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.cpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.cpp new file mode 100644 index 0000000000..64f6fd44c6 --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.cpp @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "TransformationRulesPass/TransformationRulesPassConfiguration.hpp" + +namespace microsoft +{ +namespace quantum +{ + + void TransformationRulesPassConfiguration::setup(ConfigurationManager& config) + { + config.setSectionName("Pass configuration", "Configuration of the pass and its corresponding optimisations."); + config.addParameter(delete_dead_code_, "delete-dead-code", "Deleted dead code."); + config.addParameter(clone_functions_, "clone-functions", "Clone functions to ensure correct qubit allocation."); + config.addParameter( + transform_execution_path_only_, "transform-execution-path-only", "Transform execution paths only."); + + config.addParameter( + max_recursion_, "max-recursion", "Defines the maximum recursion when unrolling the execution path"); + + config.addParameter( + assume_no_exceptions_, "assume-no-except", "Assumes that no exception will occur during runtime."); + + config.addParameter(reuse_qubits_, "reuse-qubits", "Use to define whether or not to reuse qubits."); + config.addParameter(annotate_qubit_use_, "annotate-qubit-use", "Annotate the number of qubits used"); + + config.addParameter(reuse_results_, "reuse-results", "Use to define whether or not to reuse results."); + config.addParameter(annotate_result_use_, "annotate-result-use", "Annotate the number of results used"); + + config.addParameter( + entry_point_attr_, "entry-point-attr", "Specifies the attribute indicating the entry point."); + + config.addParameter( + simplify_prior_transformation_, "simplify-prior-transform", + "When active, the IR is simplified using LLVM passes before transformation."); + + // Not implemented yet + config.addParameter(group_measurements_, "group-measurements", "NOT IMPLEMENTED - group-measurements"); + config.addParameter(one_shot_measurement_, "one-shot-measurement", "NOT IMPLEMENTED - one-shot-measurement"); + } + + TransformationRulesPassConfiguration TransformationRulesPassConfiguration::createDisabled() + { + TransformationRulesPassConfiguration ret; + ret.delete_dead_code_ = false; + ret.clone_functions_ = false; + ret.transform_execution_path_only_ = false; + ret.max_recursion_ = 512; + ret.simplify_prior_transformation_ = false; + ret.reuse_qubits_ = false; + ret.annotate_qubit_use_ = false; + ret.group_measurements_ = false; + ret.one_shot_measurement_ = false; + return ret; + } + + bool TransformationRulesPassConfiguration::shouldSimplifyPriorTransform() const + { + return simplify_prior_transformation_; + } + + bool TransformationRulesPassConfiguration::shouldDeleteDeadCode() const + { + return delete_dead_code_; + } + + bool TransformationRulesPassConfiguration::shouldCloneFunctions() const + { + return clone_functions_; + } + + bool TransformationRulesPassConfiguration::shouldTransformExecutionPathOnly() const + { + return transform_execution_path_only_; + } + + uint64_t TransformationRulesPassConfiguration::maxRecursion() const + { + return max_recursion_; + } + + bool TransformationRulesPassConfiguration::shouldReuseQubits() const + { + return reuse_qubits_; + } + + bool TransformationRulesPassConfiguration::shouldAnnotateQubitUse() const + { + return annotate_qubit_use_; + } + + bool TransformationRulesPassConfiguration::shouldReuseResults() const + { + return reuse_results_; + } + + bool TransformationRulesPassConfiguration::shouldAnnotateResultUse() const + { + return annotate_result_use_; + } + + bool TransformationRulesPassConfiguration::shouldGroupMeasurements() const + { + return group_measurements_; + } + + bool TransformationRulesPassConfiguration::oneShotMeasurement() const + { + return one_shot_measurement_; + } + + std::string TransformationRulesPassConfiguration::entryPointAttr() const + { + return entry_point_attr_; + } + + bool TransformationRulesPassConfiguration::assumeNoExceptions() const + { + return assume_no_exceptions_; + } + + bool TransformationRulesPassConfiguration::isDisabled() const + { + return ( + delete_dead_code_ == false && clone_functions_ == false && simplify_prior_transformation_ == false && + transform_execution_path_only_ == false && reuse_qubits_ == false && group_measurements_ == false && + one_shot_measurement_ == false); + } + + bool TransformationRulesPassConfiguration::operator==(TransformationRulesPassConfiguration const& ref) const + { + + return ( + delete_dead_code_ == ref.delete_dead_code_ && clone_functions_ == ref.clone_functions_ && + transform_execution_path_only_ == ref.transform_execution_path_only_ && + reuse_qubits_ == ref.reuse_qubits_ && group_measurements_ == ref.group_measurements_ && + one_shot_measurement_ == ref.one_shot_measurement_); + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp new file mode 100644 index 0000000000..67a958228e --- /dev/null +++ b/src/Passes/Source/TransformationRulesPass/TransformationRulesPassConfiguration.hpp @@ -0,0 +1,109 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" + +namespace microsoft +{ +namespace quantum +{ + /// Configuration class for the RuleTransformation pass. + class TransformationRulesPassConfiguration + { + public: + // Setup and construction + // + + /// Setup function that attached the configuration to the ConfigurationManager. + void setup(ConfigurationManager& config); + + /// Creates a configuration where all functionality is disabled. + static TransformationRulesPassConfiguration createDisabled(); + + // Configuration classes + // + + /// Tests whether all functionality is disabled for this component. + bool isDisabled() const; + + /// Testing equality of two configurations + bool operator==(TransformationRulesPassConfiguration const& ref) const; + + // Properties + // + + /// Whether or not the component should delete dead code. + bool shouldDeleteDeadCode() const; + + /// Whether or not the component should clone functions. This is relevant in relation to qubit + /// allocation if execution paths are expanded. + bool shouldCloneFunctions() const; + + /// Whether or not we assume that the code does not throw at runtime. + bool assumeNoExceptions() const; + + /// Whether or not the component should follow the execution path only or it should be applied to + /// all parts of the code. For statically allocated qubits one generally wants to follow the + /// execution path whereas it makes more sense to apply to all parts of the code for dynamic qubit + /// allocation. + bool shouldTransformExecutionPathOnly() const; + + /// The maximum recursion acceptable when unrolling the execution path. + uint64_t maxRecursion() const; + + /// Whether or not to reuse qubits. + bool shouldReuseQubits() const; + + /// Whether or not to annotate entry point with the number of qubits they use. + bool shouldAnnotateQubitUse() const; + + /// Whether or not to reuse result registers. + bool shouldReuseResults() const; + + /// Whether or not to annotate entry point with the number of results they use. + bool shouldAnnotateResultUse() const; + + /// Whether or not the component should attempt to group measurements. + bool shouldGroupMeasurements() const; + + /// Whether or not the target supports measurement (and result interpretation) during the circuit + /// execution. + bool oneShotMeasurement() const; + + /// Whether or not simplify the IR using LLVM passes prior to transforming the IR. + bool shouldSimplifyPriorTransform() const; + + /// Attribute which indicate that a function is the entry point. + std::string entryPointAttr() const; + + private: + // Code expansion and trimming + // + + bool delete_dead_code_{true}; + bool clone_functions_{true}; + bool transform_execution_path_only_{true}; + uint64_t max_recursion_{512}; + std::string entry_point_attr_{"InteropFriendly"}; + + bool simplify_prior_transformation_{true}; + + // Branching + bool assume_no_exceptions_{false}; + + // Allocation options + // + bool reuse_qubits_{true}; + bool annotate_qubit_use_{true}; + bool reuse_results_{true}; + bool annotate_result_use_{true}; + + // Measurement + // + bool group_measurements_{false}; + bool one_shot_measurement_{true}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.cpp b/src/Passes/Source/ValidationPass/ValidationPass.cpp new file mode 100644 index 0000000000..491d5bedb6 --- /dev/null +++ b/src/Passes/Source/ValidationPass/ValidationPass.cpp @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "ValidationPass/ValidationPass.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include + +namespace microsoft +{ +namespace quantum +{ + llvm::PreservedAnalyses ValidationPass::run(llvm::Module& module, llvm::ModuleAnalysisManager& /*mam*/) + { + + for (auto& function : module) + { + for (auto& block : function) + { + for (auto& instr : block) + { + auto opname = instr.getOpcodeName(); + if (opcodes_.find(opname) != opcodes_.end()) + { + ++opcodes_[opname]; + } + else + { + opcodes_[opname] = 1; + } + + auto call_instr = llvm::dyn_cast(&instr); + if (call_instr != nullptr) + { + auto f = call_instr->getCalledFunction(); + if (f == nullptr) + { + continue; + } + + auto name = static_cast(f->getName()); + if (f->isDeclaration()) + { + if (external_calls_.find(name) != external_calls_.end()) + { + ++external_calls_[name]; + } + else + { + external_calls_[name] = 1; + } + } + else + { + if (internal_calls_.find(name) != internal_calls_.end()) + { + ++internal_calls_[name]; + } + else + { + internal_calls_[name] = 1; + } + } + } + } + } + } + + bool raise_exception = false; + if (config_.whitelistOpcodes()) + { + auto const& allowed_ops = config_.allowedOpcodes(); + for (auto const& k : opcodes_) + { + if (allowed_ops.find(k.first) == allowed_ops.end()) + { + logger_->error("'" + k.first + "' is not allowed for this profile."); + } + } + } + + if (config_.whitelistOpcodes()) + { + auto const& allowed_functions = config_.allowedExternalCallNames(); + for (auto const& k : external_calls_) + { + if (allowed_functions.find(k.first) == allowed_functions.end()) + { + logger_->error("'" + k.first + "' is not allowed for this profile."); + } + } + } + + if (!config_.allowInternalCalls() && !internal_calls_.empty()) + { + logger_->error("Calls to custom defined functions not allowed."); + raise_exception = true; + } + + if (raise_exception) + { + throw std::runtime_error("QIR is not valid within the defined profile"); + } + + return llvm::PreservedAnalyses::all(); + } + + bool ValidationPass::isRequired() + { + return true; + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPass.hpp b/src/Passes/Source/ValidationPass/ValidationPass.hpp new file mode 100644 index 0000000000..80b807f2d9 --- /dev/null +++ b/src/Passes/Source/ValidationPass/ValidationPass.hpp @@ -0,0 +1,61 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/ILogger.hpp" +#include "Profile/Profile.hpp" +#include "QatTypes/QatTypes.hpp" +#include "ValidationPass/ValidationPassConfiguration.hpp" + +#include "Llvm/Llvm.hpp" + +#include +#include +#include + +namespace microsoft +{ +namespace quantum +{ + + class ValidationPass : public llvm::PassInfoMixin + { + public: + using Instruction = llvm::Instruction; + using Value = llvm::Value; + using ILoggerPtr = std::shared_ptr; + + // Construction and destruction configuration. + // + + explicit ValidationPass(ValidationPassConfiguration const& cfg, ILoggerPtr const& logger = nullptr) + : config_{cfg} + , logger_{logger} + { + } + + /// Copy construction is banned. + ValidationPass(ValidationPass const&) = delete; + + /// We allow move semantics. + ValidationPass(ValidationPass&&) = default; + + /// Default destruction. + ~ValidationPass() = default; + + llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager& mam); + /// Whether or not this pass is required to run. + static bool isRequired(); + + private: + ValidationPassConfiguration config_{}; + + std::unordered_map opcodes_; + std::unordered_map external_calls_; + std::unordered_map internal_calls_; + + ILoggerPtr logger_{nullptr}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp new file mode 100644 index 0000000000..44c86ecf20 --- /dev/null +++ b/src/Passes/Source/ValidationPass/ValidationPassConfiguration.hpp @@ -0,0 +1,109 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Commandline/ConfigurationManager.hpp" +#include "QatTypes/QatTypes.hpp" + +namespace microsoft +{ +namespace quantum +{ + + class ValidationPassConfiguration + { + public: + using Set = std::unordered_set; + // Setup and construction + // + + /// Setup function that adds the configuration flags to the ConfigurationManager. See the + /// ConfigurationManager documentation for more details on how the setup process is implemented. + void setup(ConfigurationManager& config) + { + config.setSectionName("Validation configuration", ""); + config.addParameter( + allow_internal_calls_, "allow-internal-calls", "Whether or not internal calls are allowed."); + config.addParameter( + save_report_to_, "save-validation-report", "Saves the validation report to specified filename."); + } + + static ValidationPassConfiguration fromProfileName(String const& name) + { + auto ret = ValidationPassConfiguration(); + if (name == "generic") + { + ret.allow_internal_calls_ = true; + ret.whitelist_external_calls_ = false; + ret.whitelist_opcodes_ = false; + } + else if (name == "base") + { + ret.allow_internal_calls_ = false; + ret.whitelist_external_calls_ = true; + ret.whitelist_opcodes_ = true; + ret.opcodes_ = Set{"br", "call", "unreachable", "ret", "phi", "select"}; + ret.external_calls_ = Set{ + "__quantum__qis__mz__body", "__quantum__qis__read_result__body", + "__quantum__qis__reset__body", "__quantum__qis__z__body", + "__quantum__qis__s__adj", "__quantum__qis__dumpregister__body", + "__quantum__qis__y__body", "__quantum__qis__x__body", + "__quantum__qis__t__body", "__quantum__qis__cz__body", + "__quantum__qis__s__body", "__quantum__qis__h__body", + "__quantum__qis__cnot__body", "__quantum__qis__sqrt__body", + "__quantum__qis__crz__body", "__quantum__qis__rz__body", + "__quantum__qis__arcsin__body", "__quantum__qis__drawrandomint__body", + "__quantum__qis__rx__body", "__quantum__qis__m__body", + "__quantum__qis__t__adj", + + }; + } + else + { + throw std::runtime_error("Invalid profile " + name); + } + return ret; + } + + Set const& allowedOpcodes() const + { + return opcodes_; + } + + Set const& allowedExternalCallNames() const + { + return external_calls_; + } + + bool allowInternalCalls() const + { + return allow_internal_calls_; + } + + bool whitelistOpcodes() const + { + return whitelist_opcodes_; + } + + bool whitelistExternalCalls() const + { + return whitelist_external_calls_; + } + + String const& saveReportTo() const + { + return save_report_to_; + } + + private: + Set opcodes_{}; + Set external_calls_{}; + String save_report_to_{""}; + + bool whitelist_opcodes_{true}; + bool whitelist_external_calls_{true}; + bool allow_internal_calls_{false}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.cpp b/src/Passes/Source/Validator/Validator.cpp new file mode 100644 index 0000000000..43a91b5094 --- /dev/null +++ b/src/Passes/Source/Validator/Validator.cpp @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/CommentLogger.hpp" +#include "Logging/ILogger.hpp" +#include "Logging/LogCollection.hpp" +#include "ValidationPass/ValidationPass.hpp" +#include "Validator/Validator.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + Validator::Validator(ValidationPassConfiguration const& cfg, bool debug, llvm::TargetMachine* target_machine) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , logger_{nullptr} + { + + pass_builder_ = std::make_unique(target_machine); + + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_->crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + + // Checking if we need to save the log to a file + if (!cfg.saveReportTo().empty()) + { + logger_ = std::make_shared(); + save_to_filename_ = cfg.saveReportTo(); + + module_pass_manager_.addPass(ValidationPass(cfg, logger_)); + } + else + { + // Our default is a pass that logs errors via comments + module_pass_manager_.addPass(ValidationPass(cfg, std::make_shared())); + } + } + + bool Validator::validate(llvm::Module& module) + { + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); + + if (result.IRBroken) + { + if (logger_) + { + logger_->error("Fatal error: Invalid IR."); + } + + saveReportToFileIfNeeded(); + return false; + } + + try + { + module_pass_manager_.run(module, module_analysis_manager_); + } + catch (std::exception const& e) + { + if (logger_) + { + logger_->error("Fatal error: " + static_cast(e.what())); + } + + saveReportToFileIfNeeded(); + return false; + } + + saveReportToFileIfNeeded(); + return true; + } + + llvm::PassBuilder& Validator::passBuilder() + { + return *pass_builder_; + } + + llvm::LoopAnalysisManager& Validator::loopAnalysisManager() + { + return loop_analysis_manager_; + } + + llvm::FunctionAnalysisManager& Validator::functionAnalysisManager() + { + return function_analysis_manager_; + } + + llvm::CGSCCAnalysisManager& Validator::gsccAnalysisManager() + { + return gscc_analysis_manager_; + } + + llvm::ModuleAnalysisManager& Validator::moduleAnalysisManager() + { + return module_analysis_manager_; + } + + void Validator::saveReportToFileIfNeeded() + { + if (!save_to_filename_.empty() && logger_) + { + std::fstream fout(save_to_filename_, std::ios::out); + bool not_first = false; + + fout << "["; + for (auto& message : logger_->messages()) + { + if (not_first) + { + fout << ","; + } + fout << "\n"; + fout << " {\n"; + + switch (message.type) + { + case LogCollection::Type::Debug: + fout << " \"type\": \"debug\",\n"; + break; + case LogCollection::Type::Info: + fout << " \"type\": \"info\",\n"; + break; + case LogCollection::Type::Warning: + fout << " \"type\": \"warning\",\n"; + break; + case LogCollection::Type::Error: + fout << " \"type\": \"error\",\n"; + break; + case LogCollection::Type::InternalError: + fout << " \"type\": \"internalError\",\n"; + break; + } + + fout << " \"message\": \"" << message.message << "\",\n"; + fout << " \"location\": {\n"; + fout << " \"name\": \"" << message.location.name << "\",\n"; + fout << " \"row\": " << message.location.row << ",\n"; + fout << " \"col\": " << message.location.col << "\n"; + fout << " }\n"; + fout << " }"; + not_first = true; + } + fout << "\n]\n"; + + fout.close(); + } + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.cpp.orig b/src/Passes/Source/Validator/Validator.cpp.orig new file mode 100644 index 0000000000..5a2af94d04 --- /dev/null +++ b/src/Passes/Source/Validator/Validator.cpp.orig @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "Logging/CommentLogger.hpp" +#include "Logging/ILogger.hpp" +#include "Logging/LogCollection.hpp" +#include "ValidationPass/ValidationPass.hpp" +#include "Validator/Validator.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + Validator::Validator(ValidationPassConfiguration const& cfg, bool debug, llvm::TargetMachine* target_machine) + : loop_analysis_manager_{debug} + , function_analysis_manager_{debug} + , gscc_analysis_manager_{debug} + , module_analysis_manager_{debug} + , logger_{nullptr} + { + + pass_builder_ = std::make_unique(target_machine); + + pass_builder_->registerModuleAnalyses(module_analysis_manager_); + pass_builder_->registerCGSCCAnalyses(gscc_analysis_manager_); + pass_builder_->registerFunctionAnalyses(function_analysis_manager_); + pass_builder_->registerLoopAnalyses(loop_analysis_manager_); + + pass_builder_->crossRegisterProxies( + loop_analysis_manager_, function_analysis_manager_, gscc_analysis_manager_, module_analysis_manager_); + + // Checking if we need to save the log to a file + if (!cfg.saveReportTo().empty()) + { + logger_ = std::make_shared(); + save_to_filename_ = cfg.saveReportTo(); + + module_pass_manager_.addPass(ValidationPass(cfg, logger_)); + } + else + { + // Our default is a pass that logs errors via comments + module_pass_manager_.addPass(ValidationPass(cfg, std::make_shared())); + } + } + + bool Validator::validate(llvm::Module& module) + { + llvm::VerifierAnalysis verifier; + auto result = verifier.run(module, module_analysis_manager_); + + if (result.IRBroken) + { + if (logger_) + { + logger_->error("Fatal error: Invalid IR."); + } + + saveReportToFileIfNeeded(); + return false; + } + + try + { + module_pass_manager_.run(module, module_analysis_manager_); + } + catch (std::exception const& e) + { + if (logger_) + { + logger_->error("Fatal error: " + static_cast(e.what())); + } + + saveReportToFileIfNeeded(); + return false; + } + +<<<<<<< HEAD + saveReportToFileIfNeeded(); + return true; + } + +======= +>>>>>>> main + llvm::PassBuilder& Validator::passBuilder() + { + return *pass_builder_; + } + + llvm::LoopAnalysisManager& Validator::loopAnalysisManager() + { + return loop_analysis_manager_; + } + + llvm::FunctionAnalysisManager& Validator::functionAnalysisManager() + { + return function_analysis_manager_; + } + + llvm::CGSCCAnalysisManager& Validator::gsccAnalysisManager() + { + return gscc_analysis_manager_; + } + + llvm::ModuleAnalysisManager& Validator::moduleAnalysisManager() + { + return module_analysis_manager_; + } + + void Validator::saveReportToFileIfNeeded() + { + if (!save_to_filename_.empty() && logger_) + { + std::fstream fout(save_to_filename_, std::ios::out); + bool not_first = false; + + fout << "["; + for (auto& message : logger_->messages()) + { + if (not_first) + { + fout << ","; + } + fout << "\n"; + fout << " {\n"; + + switch (message.type) + { + case LogCollection::Type::Debug: + fout << " \"type\": \"debug\",\n"; + break; + case LogCollection::Type::Info: + fout << " \"type\": \"info\",\n"; + break; + case LogCollection::Type::Warning: + fout << " \"type\": \"warning\",\n"; + break; + case LogCollection::Type::Error: + fout << " \"type\": \"error\",\n"; + break; + case LogCollection::Type::InternalError: + fout << " \"type\": \"internalError\",\n"; + break; + } + + fout << " \"message\": \"" << message.message << "\",\n"; + fout << " \"location\": {\n"; + fout << " \"name\": \"" << message.location.name << "\",\n"; + fout << " \"row\": " << message.location.row << ",\n"; + fout << " \"col\": " << message.location.col << "\n"; + fout << " }\n"; + fout << " }"; + not_first = true; + } + fout << "\n]\n"; + + fout.close(); + } + } + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/Source/Validator/Validator.hpp b/src/Passes/Source/Validator/Validator.hpp new file mode 100644 index 0000000000..ae2ff63309 --- /dev/null +++ b/src/Passes/Source/Validator/Validator.hpp @@ -0,0 +1,92 @@ +#pragma once +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "AllocationManager/AllocationManager.hpp" +#include "AllocationManager/IAllocationManager.hpp" +#include "Logging/ILogger.hpp" +#include "Logging/LogCollection.hpp" +#include "ValidationPass/ValidationPassConfiguration.hpp" + +#include "Llvm/Llvm.hpp" + +#include + +namespace microsoft +{ +namespace quantum +{ + + /// Validator class that defines a set of rules which constitutes the profile definition. Each of + /// the rules can be used to transform a generic QIR and/or validate that the QIR is compliant with + /// said rule. + class Validator + { + public: + using ValidatorPtr = std::unique_ptr; + using LogColloectionPtr = std::shared_ptr; + + // Constructors + // + + explicit Validator( + ValidationPassConfiguration const& cfg, + bool debug, + llvm::TargetMachine* target_machine = nullptr); + + // Default construction not allowed to ensure that LLVM modules and passes are set up correctly. + // Copy construction is prohibited due to restriction on classes held by Validator. + + Validator() = delete; + Validator(Validator const&) = delete; + Validator(Validator&&) = default; + Validator& operator=(Validator const&) = delete; + Validator& operator=(Validator&&) = default; + ~Validator() = default; + + // Validator methods + // + + /// Validates that a module complies with the specified QIR profile. Returns true if the module is + /// valid and false otherwise. + bool validate(llvm::Module& module); + + protected: + using PassBuilderPtr = std::unique_ptr; + + /// Returns a reference to the pass builder. + llvm::PassBuilder& passBuilder(); + + /// Returns a reference to the loop analysis manager. + llvm::LoopAnalysisManager& loopAnalysisManager(); + + /// Returns a reference to the function analysis manager. + llvm::FunctionAnalysisManager& functionAnalysisManager(); + + /// Returns a reference to the GSCC analysis manager. + llvm::CGSCCAnalysisManager& gsccAnalysisManager(); + + /// Returns a reference to the module analysis manager. + llvm::ModuleAnalysisManager& moduleAnalysisManager(); + + private: + void saveReportToFileIfNeeded(); + + // LLVM logic to run the passes + // + + llvm::LoopAnalysisManager loop_analysis_manager_; + llvm::FunctionAnalysisManager function_analysis_manager_; + llvm::CGSCCAnalysisManager gscc_analysis_manager_; + llvm::ModuleAnalysisManager module_analysis_manager_; + + PassBuilderPtr pass_builder_; + + llvm::ModulePassManager module_pass_manager_{}; + + LogColloectionPtr logger_{nullptr}; ///< Logger to keep track of errors and warnings occurring. + String save_to_filename_{""}; + }; + +} // namespace quantum +} // namespace microsoft diff --git a/src/Passes/cmake/Library.cmake b/src/Passes/cmake/Library.cmake new file mode 100644 index 0000000000..23199cbd49 --- /dev/null +++ b/src/Passes/cmake/Library.cmake @@ -0,0 +1,55 @@ +macro(list_source_files result directory) + file(GLOB_RECURSE source RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${directory}/*.cpp) + set(filelist "") + foreach(child ${source}) + if(NOT ${child} MATCHES "(/Tests/)") + list(APPEND filelist ${child}) + endif() + endforeach() + + set(${result} ${filelist}) +endmacro() + +function (microsoft_add_library + library) + list(REMOVE_AT ARGV 0) + + set(directory ${CMAKE_CURRENT_SOURCE_DIR}/${library}) + + list_source_files(source ${directory}) + + add_library(${library} + STATIC + ${source}) + + target_include_directories( + ${library} + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/include" + ) + + + if (WIN32) + # Windows specific congure + elseif (APPLE) + # OS X specific + if(MICROSOFT_ENABLE_DYNAMIC_LOADING) + target_link_libraries(${library} + PUBLIC "$<$:-undefined dynamic_lookup>") + else() + target_link_libraries(${library} PRIVATE ${llvm_libs}) + endif(MICROSOFT_ENABLE_DYNAMIC_LOADING) + + else () + # Assuming linux + if(MICROSOFT_ENABLE_DYNAMIC_LOADING) + target_compile_options(${library} + PUBLIC "-fPIC") + else() + target_link_libraries(${library} PRIVATE ${llvm_libs}) + endif(MICROSOFT_ENABLE_DYNAMIC_LOADING) + endif () + + + +endfunction () diff --git a/src/Passes/cmake/Testing.cmake b/src/Passes/cmake/Testing.cmake new file mode 100644 index 0000000000..b8a9a7881f --- /dev/null +++ b/src/Passes/cmake/Testing.cmake @@ -0,0 +1,50 @@ +if (MICROSOFT_ENABLE_TESTS) + include(CTest) + enable_testing() +endif (MICROSOFT_ENABLE_TESTS) + + +function (_internal_add_test name source library) + if (MICROSOFT_ENABLE_TESTS) + file(GLOB_RECURSE srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${source}/*.cpp) + file(GLOB_RECURSE hdrs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${source}/*.hpp) + file(GLOB_RECURSE ipps RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${source}/*.ipp) + + add_executable(${name} ${ipps} ${hdrs} ${srcs}) + target_link_libraries(${name} PRIVATE ${llvm_libs}) + target_link_libraries(${name} PRIVATE ${library} gmock gmock_main TestTools) + + target_include_directories(${name} + PRIVATE ${MICROSOFT_ROOT_VENDOR_DIR}/googletest/googlemock/include) + + add_test(${name} + ${name} + --gtest_shuffle + --gtest_random_seed=1337) + endif (MICROSOFT_ENABLE_TESTS) +endfunction() + +function (microsoft_add_library_tests + library) + if (MICROSOFT_ENABLE_TESTS) + list(REMOVE_AT ARGV 0) + + set(directory ${CMAKE_CURRENT_SOURCE_DIR}/${library}/Tests) + set(unit_directory ${directory}/Unit) + set(integration_directory ${directory}/Integration) + + if(IS_DIRECTORY ${unit_directory}) + _internal_add_test("${library}UnitTests" ${unit_directory} ${library}) + target_link_libraries("${library}UnitTests" PRIVATE ${ARGV}) + else() + message(NOTICE "No unit tests for ${library}") + endif() + + if(IS_DIRECTORY ${integration_directory}) + _internal_add_test("${library}IntegrationTests" ${integration_directory} ${library}) + target_link_libraries("${library}IntegrationTests" PRIVATE ${ARGV}) + else() + message(NOTICE "No integration tests for ${library}") + endif() + endif (MICROSOFT_ENABLE_TESTS) +endfunction () diff --git a/src/Passes/dev-environment.yml b/src/Passes/dev-environment.yml new file mode 100644 index 0000000000..6a7b181b0b --- /dev/null +++ b/src/Passes/dev-environment.yml @@ -0,0 +1,13 @@ +# dev-environment.yml +name: qat-dev +channels: +- conda-forge +dependencies: +- python>=3.6 +- click # Anything else from requirements.txt could go here, too, + # if there's a matching conda package. +- clang +- clang-tools # Provides clang-format and clang-tidy +- pip +- pip: + - lit==12.0.1 diff --git a/src/Passes/docs/.doxybook/config.json b/src/Passes/docs/.doxybook/config.json new file mode 100644 index 0000000000..bed9226511 --- /dev/null +++ b/src/Passes/docs/.doxybook/config.json @@ -0,0 +1,13 @@ +{ + "baseUrl": "/", + "indexInFolders": true, + "linkLowercase": false, + "indexClassesName": "index", + "indexFilesName": "index", + "indexGroupsName": "index", + "indexNamespacesName": "index", + "indexRelatedPagesName": "index", + "indexExamplesName": "index", + "mainPageInRoot": true, + "mainPageName": "index" +} diff --git a/src/Passes/docs/nginx/default.conf b/src/Passes/docs/nginx/default.conf new file mode 100644 index 0000000000..dca02a15a1 --- /dev/null +++ b/src/Passes/docs/nginx/default.conf @@ -0,0 +1,19 @@ +server { + listen 80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri $uri/index.html; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/src/Passes/docs/package.json b/src/Passes/docs/package.json new file mode 100755 index 0000000000..2971d767c8 --- /dev/null +++ b/src/Passes/docs/package.json @@ -0,0 +1,19 @@ +{ + "name": "test", + "version": "0.0.1", + "description": "", + "main": "index.js", + "authors": { + "name": "", + "email": "" + }, + "repository": "/test", + "scripts": { + "dev": "vuepress dev src", + "build": "vuepress build src" + }, + "license": "MIT", + "devDependencies": { + "vuepress": "^1.5.3" + } +} diff --git a/src/Passes/docs/src/.vuepress/components/Foo/Bar.vue b/src/Passes/docs/src/.vuepress/components/Foo/Bar.vue new file mode 100755 index 0000000000..7ee8286a27 --- /dev/null +++ b/src/Passes/docs/src/.vuepress/components/Foo/Bar.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/Passes/docs/src/.vuepress/components/OtherComponent.vue b/src/Passes/docs/src/.vuepress/components/OtherComponent.vue new file mode 100755 index 0000000000..1d97c7ca8e --- /dev/null +++ b/src/Passes/docs/src/.vuepress/components/OtherComponent.vue @@ -0,0 +1,3 @@ + diff --git a/src/Passes/docs/src/.vuepress/components/demo-component.vue b/src/Passes/docs/src/.vuepress/components/demo-component.vue new file mode 100755 index 0000000000..7d49de79d0 --- /dev/null +++ b/src/Passes/docs/src/.vuepress/components/demo-component.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/Passes/docs/src/.vuepress/config.js b/src/Passes/docs/src/.vuepress/config.js new file mode 100755 index 0000000000..afc60534bc --- /dev/null +++ b/src/Passes/docs/src/.vuepress/config.js @@ -0,0 +1,61 @@ +const { description } = require("../../package"); + +module.exports = { + /** + * Ref:https://v1.vuepress.vuejs.org/config/#title + */ + title: "QIR Adaptor Tool Developer Documentation", + /** + * Ref:https://v1.vuepress.vuejs.org/config/#description + */ + description: description, + + /** + * Extra tags to be injected to the page HTML `` + * + * ref:https://v1.vuepress.vuejs.org/config/#head + */ + head: [ + ["meta", { name: "theme-color", content: "#3eaf7c" }], + ["meta", { name: "apple-mobile-web-app-capable", content: "yes" }], + [ + "meta", + { name: "apple-mobile-web-app-status-bar-style", content: "black" }, + ], + ], + + /** + * Theme configuration, here is the default theme configuration for VuePress. + * + * ref:https://v1.vuepress.vuejs.org/theme/default-theme-config.html + */ + themeConfig: { + repo: "", + editLinks: false, + docsDir: "", + editLinkText: "", + lastUpdated: false, + nav: [ + { text: "Home", link: "/" }, + { text: "Classes", link: "/Classes/" }, + { text: "Namespaces", link: "/Namespaces/" }, + { text: "Modules", link: "/Modules/" }, + { text: "Files", link: "/Files/" }, + { text: "Pages", link: "/Pages/" }, + ], + sidebar: { + "/guide/": [ + { + title: "Guide", + collapsable: false, + children: ["", "using-vue"], + }, + ], + }, + }, + + /** + * Apply plugins,ref:https://v1.vuepress.vuejs.org/zh/plugin/ + */ + plugins: ["@vuepress/plugin-back-to-top", "@vuepress/plugin-medium-zoom"], +}; diff --git a/src/Passes/docs/src/.vuepress/enhanceApp.js b/src/Passes/docs/src/.vuepress/enhanceApp.js new file mode 100755 index 0000000000..8452a86899 --- /dev/null +++ b/src/Passes/docs/src/.vuepress/enhanceApp.js @@ -0,0 +1,14 @@ +/** + * Client app enhancement file. + * + * https://v1.vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements + */ + +export default ({ + Vue, // the version of Vue being used in the VuePress app + options, // the options for the root Vue instance + router, // the router instance for the app + siteData // site metadata +}) => { + // ...apply enhancements for the site. +} diff --git a/src/Passes/docs/src/.vuepress/styles/index.styl b/src/Passes/docs/src/.vuepress/styles/index.styl new file mode 100755 index 0000000000..420feb93f9 --- /dev/null +++ b/src/Passes/docs/src/.vuepress/styles/index.styl @@ -0,0 +1,8 @@ +/** + * Custom Styles here. + * + * ref:https://v1.vuepress.vuejs.org/config/#index-styl + */ + +.home .hero img + max-width 450px!important diff --git a/src/Passes/docs/src/.vuepress/styles/palette.styl b/src/Passes/docs/src/.vuepress/styles/palette.styl new file mode 100755 index 0000000000..6490cb359a --- /dev/null +++ b/src/Passes/docs/src/.vuepress/styles/palette.styl @@ -0,0 +1,10 @@ +/** + * Custom palette here. + * + * ref:https://v1.vuepress.vuejs.org/zh/config/#palette-styl + */ + +$accentColor = #3eaf7c +$textColor = #2c3e50 +$borderColor = #eaecef +$codeBgColor = #282c34 diff --git a/src/Passes/docs/src/DeveloperGuide/ArchitectureOverview.md b/src/Passes/docs/src/DeveloperGuide/ArchitectureOverview.md new file mode 100644 index 0000000000..a090ba703a --- /dev/null +++ b/src/Passes/docs/src/DeveloperGuide/ArchitectureOverview.md @@ -0,0 +1,55 @@ +# Architecture Overview + +This document assumes familiarity with LLVM, [LLVM intermediate representation (IR)](https://llvm.org/docs/LangRef.html), LLVM passes and the `opt` which is used to apply passes to IRs. We also assume that the reader is familiar with the [QIR specification](https://github.com/microsoft/qsharp-language/tree/main/Specifications/QIR), the conventions used for functions and its opaque types. We further assume that the reader is familiar with basic C++. This is in particular true later on when we dig into the details of building pass components. Throughout this document we will assume that any reference to a QIR, is a valid within the specification requirements. + +The aim of this document is to walk the reader through the vision and architecture of the QIR adaptor tool (QAT). To this end, we will be discussing how QAT uses both native and custom written LLVM passes to transform generic QIRs into ones which are targeted specific platforms and/or capabilities. + +We refer to any generic QIR as just "the QIR" or the generic QIR where as those target for specific platforms and/or capabilities, we call specialised QIRs. The description of the requirements for the specialised QIR we call a QIR profile. When we talk about applying a profile to a generic QIR, we talk about the process which transform the generic QIR into the specialised one. Likewise, when we talk about validating that a specialised QIR fulfils the description of a profile. + +In building QAT, we note that there are two main challenges to overcome: 1) Applying a profile to a generic QIR and 2) validating that a QIR is compliant with a profile specification. We may on occasion refer to the former as a transformation and the latter as an analysis to clarify the similarity to LLVM passes. The architecture described in this document attempts to address both of these challenges in way that we believe to be customisable and scalable in terms of profile requirements. + +Before digging into the details of the design of QAT, we first note that LLVMs `opt` has many of the properties that we desire: Modularised, extendable in a non-invasive manner and differentiates between analysis and transformation. The downsides to `opt` is that we cannot pass a configuration to the individual passes, it is difficult to control which concrete passes are ran and, under the assumption that a profile is described by a collection of passes, there is no elegant way to bundle these into a single argument. In our design, it will be our goal to preserve the good aspects `opt` while adding the capabilities we miss to make profile transformations and validation. + +Before spelling the system requirements out, we consider a couple of examples of what we may need for functionality. + +## Example: Function inlining + +Let us first consider the case of quantum architecture that does not support classical function calls. That is, a valid program must be all inlined. This is a task that can be handled by `opt` by supplying the command line argument `--always-inline`. This flag turns the inline pipeline on and attempts to inline as many function calls as possible. For QAT to be a useful tool, we would want a similar mechanism that allows to activate or deactivate existing (and new) LLVM passes. We would thus need something like + +```sh +qat --always-inline --apply -S filename.ll +``` + +where `--apply` tells the tool to apply the profile and `-S` tells the tool to emit human readable LLVM IR code. Furthermore, if the inline pass is provided as an external module, we would need to be able load it + +```sh +qat --always-inline --load path/to/lib.(dylib|so|dll) --apply -S filename.ll +``` + +We note that from a developer point of view, the underlying code would also need a way to let QAT know that it expects a command line argument `--always-inline/--no-always-inline`. + +## Example: Static qubit allocation + +To get a better understanding of the problem at hand, lets examine another example: Qubit allocation. As we run our quantum program, we may use a simulator or we may deploy it on one of the hardware efforts. Depending on whether we are running in one environment or the other, qubits are different entities: In a computer simulation they are often objects. They could for instance be allocated on the heap in a non-sequential manner. In this context, it makes sense to talk about a qubits life time through instructions that allocates and releases them. On hardware, on the other hand, qubits are physical entities typically sequentially enumerated from 0 to N. Physical qubits may (or may not) have the constraint some qubits are unavailable to the user. Though not always, hardware may further have the constraint that user can only perform a single measurement at the end of the program execution. This means that qubits cannot be reused within one program execution. + +This puts requirements on what we may need from static qubit allocation. For any static allocation, we would need at least following information: + +- Whether or not to map qubits to fixed integers +- Reuse qubits or not +- List unavailable qubits + +It is not hard to imagine that this could be extended even further by imposing customised allocation schemes. In contrast to the previous example, this example requires a much more detailed configuration to define the mode of operation. One could for instance imagine something along the lines of + +```sh +qat --use-static-allocation --reuse-qubits --defect-qubits 3,7,9 --max-qubits 10 --apply -S filename.ll +``` + +Hence, unlike normal LLVM passes, we will need a detailed configuration to be passed along with the transformation. + +## Design requirements + +To distinguish between LLVM passes and QAT extensions, we will refer to QAT extensions as profile components. A profile component may consist of several passes and furthermore should be accompanied by a configuration to describe its behaviour. Like LLVM `opt` we require that QAT must be extensible through dynamic libraries. This allow third party to easily extend the tool to their needs while benefiting from the components that QAT ships with. + +## Architecture description + +TODO(tfr): Yet to be written diff --git a/src/Passes/docs/src/DeveloperGuide/CodeQuality.md b/src/Passes/docs/src/DeveloperGuide/CodeQuality.md new file mode 100644 index 0000000000..b35bf61e34 --- /dev/null +++ b/src/Passes/docs/src/DeveloperGuide/CodeQuality.md @@ -0,0 +1,166 @@ +# Code quality and continuous integration + +## Using the manage tool + +Before making a pull request with changes to this library, please ensure that style checks passes, that the code compiles, +unit test passes and that there are no erros found by the static analyser. + +To setup the CI environment, run following commands + +```sh +virtualenv develop__venv +source develop__venv/bin/activate +pip install -r requirements.txt +``` + +These adds the necessary environment variables to ensure that you have the `tasks_ci` package and all required dependencies. + +To check the style, run + +```sh +./manage stylecheck +``` + +To test that the code compiles and tests passes run + +```sh +./manage test +``` + +Finally, to analyse the code, run + +```sh +./manage lint +``` + +You can run all processes by running: + +```sh +./manage runci +``` + +As `clang-tidy` and `clang-format` acts slightly different from version to version and on different platforms, it is recommended +that you use a docker image to perform these steps. TODO(TFR): The docker image is not added yet and this will be documented in the future. + +## Running tests + +In order to run the tests, you first need to build the library. Assuming that this is already done and the corresponding build is in `Debug/`, run the tests from the `Debug` folder: + +``` +lit tests/ -v +-- Testing: 2 tests, 2 workers -- +PASS: Quantum-Passes :: QirAllocationAnalysis/case1.ll (1 of 2) +PASS: Quantum-Passes :: QirAllocationAnalysis/case2.ll (2 of 2) + +Testing Time: 0.27s + Passed: 2 +``` + +The C++ test suite can also be ran from the debug by first building all targets: + +```sh +cmake .. +make +``` + +and then running following command: + +```sh +ctest +``` + +## Writing C++ tests + +TODO(tfr): Write this section + +## Modifying code quality requirements + +The continuous integration component includes: + +1. Style formatting to ensure that everything looks the same. This includes checking that relevant copyrights are in place. +2. Static analysis +3. Unit testing + +The automatic style enforcement is configurable with the ability to easily add or remove rules. Currently the source pipelines are defined as: + +```python +SOURCE_PIPELINES = [ + { + "name": "C++ Main", + "src": path.join(PROJECT_ROOT, "Source"), + + "pipelines": { + "hpp": [ + require_pragma_once, + enforce_cpp_license, + enforce_formatting + ], + "cpp": [ + enforce_cpp_license, + enforce_formatting + ] + } + }, + # ... +] +``` + +This part defines pipelines for `.hpp` files and `.cpp` files allowing the developer to add such requirements as having copyright in the op of the source file and ensure that formatting follows that given by `.clang-format`. + +Each of these CI stages can be executed individually using `./manage` or you can run the entire CI process by invoking `./manage runci`. An example of what this may look like is here: + +```zsh +./manage runci + +2021-07-21 14:38:04,896 - FormatChecker - ERROR - /Users/tfr/Documents/Projects/qsharp-compiler/src/QsPasses/src/OpsCounter/OpsCounter.cpp was not correctly formatted. +2021-07-21 14:38:04,899 - FormatChecker - ERROR - Your code did not pass formatting. + +./manage stylecheck --fix-issues +./manage runci + +-- Found LLVM 11.1.0 +-- Using LLVMConfig.cmake in: /usr/local/opt/llvm@11/lib/cmake/llvm +-- Configuring done +-- Generating done +-- Build files have been written to: /Users/tfr/Documents/Projects/qsharp-compiler/src/QsPasses/Debug +Consolidate compiler generated dependencies of target QSharpPasses +[ 50%] Building CXX object CMakeFiles/QSharpPasses.dir/src/OpsCounter/OpsCounter.cpp.o +[100%] Linking CXX shared library libQSharpPasses.dylib +ld: warning: directory not found for option '-L/usr/local/opt/llvm/lib' +[100%] Built target QSharpPasses +/Users/tfr/Documents/Projects/qsharp-compiler/src/QsPasses/src/OpsCounter/OpsCounter.cpp:29:7: error: invalid case style for class 'LegacyOpsCounterPass' [readability-identifier-naming,-warnings-as-errors] +class LegacyOpsCounterPass : public FunctionPass + ^~~~~~~~~~~~~~~~~~~~ + CLegacyOpsCounterPass +113345 warnings generated. +Suppressed 113345 warnings (113344 in non-user code, 1 NOLINT). +Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. +1 warning treated as error +2021-07-21 14:38:40,191 - Linter - ERROR - /Users/tfr/Documents/Projects/qsharp-compiler/src/QsPasses/src/OpsCounter/OpsCounter.cpp failed static analysis + +# ISSUES FIXED MANUALLY +./manage runci + +-- Found LLVM 11.1.0 +-- Using LLVMConfig.cmake in: /usr/local/opt/llvm@11/lib/cmake/llvm +-- Configuring done +-- Generating done +-- Build files have been written to: /Users/tfr/Documents/Projects/qsharp-compiler/src/QsPasses/Debug +Consolidate compiler generated dependencies of target QSharpPasses +[ 50%] Building CXX object CMakeFiles/QSharpPasses.dir/src/OpsCounter/OpsCounter.cpp.o +[100%] Linking CXX shared library libQSharpPasses.dylib +ld: warning: directory not found for option '-L/usr/local/opt/llvm/lib' +[100%] Built target QSharpPasses +-- Found LLVM 11.1.0 +-- Using LLVMConfig.cmake in: /usr/local/opt/llvm@11/lib/cmake/llvm +-- Configuring done +-- Generating done +-- Build files have been written to: /Users/tfr/Documents/Projects/qsharp-compiler/src/QsPasses/Debug +Consolidate compiler generated dependencies of target QSharpPasses +[100%] Built target QSharpPasses +********************************* +No test configuration file found! +********************************* +``` + +The key idea here is to make it extremely easy to be compliant with the style guide, correct any issues that might come as a result of static analysis and at the same time enforce this when a PR is made. diff --git a/src/Passes/docs/src/DeveloperGuide/ConfigurationLibrary.md b/src/Passes/docs/src/DeveloperGuide/ConfigurationLibrary.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Passes/docs/src/DeveloperGuide/DeveloperFAQ.md b/src/Passes/docs/src/DeveloperGuide/DeveloperFAQ.md new file mode 100644 index 0000000000..a9b2cd74d4 --- /dev/null +++ b/src/Passes/docs/src/DeveloperGuide/DeveloperFAQ.md @@ -0,0 +1,29 @@ +# Developer FAQ + +## Pass does not load + +One error that you may encounter is that an analysis pass does not load with output similar to this: + +```sh +opt -load-pass-plugin ../../Debug/libQSharpPasses.dylib -enable-debugify --passes="operation-counter" -disable-output classical-program.bc +Failed to load passes from '../../Debug/libQSharpPasses.dylib'. Request ignored. +opt: unknown pass name 'operation-counter' +``` + +This is likely becuase you have forgotten to instantiate static class members. For instance, in the case of an instance of `llvm::AnalysisInfoMixin` you are required to have a static member `Key`: + +```cpp +class COpsCounterPass : public llvm::AnalysisInfoMixin { +private: + static llvm::AnalysisKey Key; //< REQUIRED by llvm registration + friend struct llvm::AnalysisInfoMixin; +}; +``` + +If you forget to instantiate this variable in your corresponding `.cpp` file, + +```cpp +// llvm::AnalysisKey COpsCounterPass::Key; //< Uncomment this line to make everything work +``` + +everything will compile, but the pass will fail to load. There will be no linking errors either. diff --git a/src/Passes/docs/src/DeveloperGuide/ProfileTransformationCpp.md b/src/Passes/docs/src/DeveloperGuide/ProfileTransformationCpp.md new file mode 100644 index 0000000000..6c730ec307 --- /dev/null +++ b/src/Passes/docs/src/DeveloperGuide/ProfileTransformationCpp.md @@ -0,0 +1,98 @@ +# Creating a profile transformation in C++ + +## Profile transformation + +TODO(tfr): Yet to be written + +## Profile transformation as pass + +As an example of how one can implement a new profile pass, we here show the implementation details of our example pass which allows mapping the teleportation code to the base profile: + +```c++ + pb.registerPipelineParsingCallback([](StringRef name, FunctionPassManager &fpm, + ArrayRef /*unused*/) { + // Base profile + if (name == "restrict-qir") + { + RuleSet rule_set; + + // Defining the mapping + auto factory = RuleFactory(rule_set); + + factory.useStaticQuantumArrayAllocation(); + factory.useStaticQuantumAllocation(); + factory.useStaticResultAllocation(); + + factory.optimiseBranchQuatumOne(); + // factory.optimiseBranchQuatumZero(); + + factory.disableReferenceCounting(); + factory.disableAliasCounting(); + factory.disableStringSupport(); + + fpm.addPass(TransformationRulePass(std::move(rule_set))); + return true; + } + + return false; + }); + }}; +``` + +Transformations of the IR will happen on the basis of what rules are added to the rule set. The purpose of the factory is to make easy to add rules that serve a single purpose as well as making a basis for making rules unit testable. + +## Implementing new rules + +Implementing new rules consists of two steps: Defining a pattern that one wish to replace and implementing the corresponding replacement logic. Inside a factory member function, this look as follows: + +```c++ + auto get_element = + Call("__quantum__rt__array_get_element_ptr_1d", "arrayName"_cap = _, "index"_cap = _); + auto cast_pattern = BitCast("getElement"_cap = get_element); + auto load_pattern = Load("cast"_cap = cast_pattern); + + addRule({std::move(load_pattern), access_replacer}); +``` + +where `addRule` adds the rule to the current rule set. + +## Capturing patterns + +The pattern defined in this snippet matches IR like: + +```c++ + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 0) + %1 = bitcast i8* %0 to %Qubit** + %2 = load %Qubit*, %Qubit** %1, align 8 +``` + +In the above rule, the first and a second argument of `__quantum__rt__array_get_element_ptr_1d` is captured as `arrayName` and `index`, respectively. Likewise, the bitcast instruction is captured as `cast`. Each of these captures will be available inside the replacement function `access_replacer`. + +## Implementing replacement logic + +After a positive match is found, the lead instruction alongside a IRBuilder, a capture table and a replacement table is passed to the replacement function. Here is an example on how one can access the captured variables to perform a transformation of the IR: + +```c++ + auto access_replacer = [qubit_alloc_manager](Builder &builder, Value *val, Captures &cap, + Replacements &replacements) { + // ... + auto cst = llvm::dyn_cast(cap["index"]); + // ... + auto llvm_size = cst->getValue(); + auto offset = qubit_alloc_manager->getOffset(cap["arrayName"]->getName().str()); + + auto idx = llvm::APInt(llvm_size.getBitWidth(), llvm_size.getZExtValue() + offset); + auto new_index = llvm::ConstantInt::get(builder.getContext(), idx); + auto instr = new llvm::IntToPtrInst(new_index, ptr_type); + instr->takeName(val); + + // Replacing the lead instruction with a the new instruction + replacements.push_back({llvm::dyn_cast(val), instr}); + + // Deleting the getelement and cast operations + replacements.push_back({llvm::dyn_cast(cap["getElement"]), nullptr}); + replacements.push_back({llvm::dyn_cast(cap["cast"]), nullptr}); + + return true; + }; +``` diff --git a/src/Passes/docs/src/DeveloperGuide/WritingComponent.md b/src/Passes/docs/src/DeveloperGuide/WritingComponent.md new file mode 100644 index 0000000000..2ce0783183 --- /dev/null +++ b/src/Passes/docs/src/DeveloperGuide/WritingComponent.md @@ -0,0 +1,181 @@ +# Tutorial: Writing a new component + +In this tutorial we will develop a new QAT profile component. We will make the component a separate library which is dynamically loaded through the command line interface. All examples in this tutorial can be found in `ComponentExamples`. + +Our first "component" will be a boilerplate hello world component which serves the purpose of giving the reader an understanding of how to define configurations for our component. We will demonstrate how to use this component from the command line. + +For our second component, we will use a standard LLVM pass to demonstrate how to load these. We will show how the registered configuration can be used to enable or disable the pass. To show that the effect of the pass, we use the inliner pipeline together with the `QirExamples/LoopRecursion`. We will see how enabling the pass results in inlining all the function calls. As QAT ships with a built-in inliner pass, it is important to remember to disable this to see the effect of our custom pass. + +## Hello world + +Our first component will not do anything except for printing out a custom message upon configuring the profile. To this end, we need a configuration which allows the user to specify the message and we capture this configuration in a class which we name `HelloWorldConfig`: + +```c++ +using String = std::string; +class HelloWorldConfig +{ +public: + // ... +private: + String message_{"Hello world"}; +}; +``` + +We note the default value of our configuration is captured through the initialisation of the class member. That is, if not overridden by the command line arguments, the message will be `"Hello world"`. + +To fulfil the concept of being a configuration, a configuration must implement a `setup` function taking a reference to a `ConfigurationManager` as its only argument. For our configuration, this looks like + +```c++ +class HelloWorldConfig +{ +public: + void setup(ConfigurationManager &config) + { + config.setSectionName("Hello world configuration", + "Demonstrating how configuration works."); + config.addParameter(message_, "message", + "Message which is printed when setting the component up."); + } + + // ... +}; +``` + +The purpose of the `setup(config)` function is to inform the configuration manager about what the name of the configuration section and its description is as well as defining all settings and bind them to C++ variables. The benefit of this approach is that all configuration parameters for the component will be available immediately after the component is loaded by the tool. + +The final code to manage the configuration reads: + +```c++ +class HelloWorldConfig +{ +public: + using String = std::string; + + void setup(ConfigurationManager &config) + { + config.setSectionName("Hello world configuration", + "Demonstrating how configuration works."); + config.addParameter(message_, "message", + "Message which is printed when setting the component up."); + } + + String const& message() const + { + return message_; + } + +private: + String message_{"Hello world"}; +}; +``` + +With the configuration in place, the next thing we concern ourselves with is loading the component. This is the functionality that registers the configuration together with an ID and a profile setup function. In our case, the setup function should just print a message given a `HelloWorldConfig` instance. The corresponding component registration reads: + +```c++ +extern "C" void loadComponent(IProfileGenerator *generator) +{ + generator->registerProfileComponent( + "hello-world", + [](HelloWorldConfig const &cfg, IProfileGenerator * /*generator*/, Profile & /*profile*/) { + std::cout << "Message: " << cfg.message() << std::endl; + }); +} +``` + +In this example, we will only concern ourselves with how to use the configuration and we will ignore `generator` and `profile` for now. The full source code to this example can be found in `ComponentExamples/HelloWorld` and it can be compiled through following steps (startig from the Passes root folder): + +```sh +mkdir Debug +cd Debug +cmake .. +make HelloWorld +``` + +This will generate a `HelloWorld` dynamic library with path `./ComponentExamples/libHelloWorld.(dylib|so|dll)`. + +## Loading the component + +Executing `qat` and loading the `libHelloWorld` library, we see that our new settings are added to help page: + +```sh +% ./Source/Apps/qat --load ./ComponentExamples/libHelloWorld.dylib +Usage: ./Source/Apps/qat [options] filename + +... + +Hello world configuration - Demonstration configuration for building a component boilerplate. + +--message Message which is printed when setting the component up. Default: Hello world + + +... +``` + +For the next part, we assume that you have a QIR located in `path/to/example.ll`. To test that the setup function is invoked upon setting the profile up, we run + +``` + % ./Source/Apps/qat --load ./ComponentExamples/libHelloWorld.dylib path/to/example.ll +Message: Hello world +``` + +## Creating a Pass Component + +Next, we make a component that just runs a single LLVM pass. We we will use the inline pipeline to this end. + +We create a single option for activating the pass: + +```c++ +class InlinerConfig +{ +public: + using String = std::string; + + void setup(ConfigurationManager &config) + { + config.setSectionName("Inliner component", "Adds the LLVM Always Inline Pass to the profile"); + config.addParameter(inline_, "custom-inliner", "Activating the custom inliner."); + } + + bool shouldInline() const + { + return inline_; + } + +private: + bool inline_{false}; ///< Default behaviour is that we do not add the inliner pass +}; +``` + +The implementation itself is + +```c++ +extern "C" void loadComponent(IProfileGenerator *generator) +{ + generator->registerProfileComponent( + "inliner", [](InlinerConfig const &cfg, IProfileGenerator *ptr, Profile & /*profile*/) { + if (cfg.shouldInline()) + { + auto &module_pass_manager = ptr->modulePassManager(); + + // Adds the inline pipeline + auto &pass_builder = ptr->passBuilder(); + auto inliner_pass = pass_builder.buildInlinerPipeline( + ptr->optimisationLevel(), llvm::PassBuilder::ThinLTOPhase::None, ptr->debug()); + module_pass_manager.addPass(std::move(inliner_pass)); + } + }); +} + +``` + +To run this pass, + +```sh +./Source/Apps/qat --load ./ComponentExamples/libInlinePassComponent.dylib ../QirExamples/LoopRecursion/QSharpVersion/qir/Example.ll --S --apply --no-always-inline --custom-inliner +``` + +Compare the output against + +```sh +./Source/Apps/qat --load ./ComponentExamples/libInlinePassComponent.dylib ../QirExamples/LoopRecursion/QSharpVersion/qir/Example.ll --S --apply --no-always-inline +``` diff --git a/src/Passes/docs/src/DeveloperGuide/WritingRuleTests.md b/src/Passes/docs/src/DeveloperGuide/WritingRuleTests.md new file mode 100644 index 0000000000..4018fb2606 --- /dev/null +++ b/src/Passes/docs/src/DeveloperGuide/WritingRuleTests.md @@ -0,0 +1,120 @@ +# Writing rule tests + +To make it easy to write tests for transformation rules, we have created two components to ease the burden of writing tests: `DefaultProfileGenerator` and `IrManipulationTestHelper`. The `DefaultProfileGenerator` is a profile that is dynamically defined when instatiated through a configuration lambda function. + +## Creating the profile + +Creating the profile using the `DefaultProfileGenerator` is done by first defining the lambda function and then instantiating the `DefaultProfileGenerator` with the lambda function to define the profile. Using the `RuleFactory`, a profile for transforming the single qubit allocations is created as follows: + +```c++ + auto configure_profile = [](RuleSet &rule_set) { + auto factory = RuleFactory(rule_set); + + factory.useStaticQubitAllocation(); + } + + auto profile = std::make_shared(std::move(configure_profile)); +``` + +This profile is intended to transform + +``` + %qubit = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %qubit) + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + ret i8 0 +``` + +by replacing all allocations with integers and stripping all release calls + +``` + %qubit = inttoptr i64 0 to %Qubit* + tail call void @__quantum__qis__h__body(%Qubit* %qubit) + ret i8 0 +``` + +## Creating the IR + +In order to assist the testing of the above profile, we create a helper class which defines the IR we want to work on. To this end we make use of `IrManipulationTestHelper` which provides a number of shorthand functions to generate and test IR transformations. We start by defining the IR: + +```c++ + auto ir_manip = std::make_shared(); + + ir_manip->declareOpaque("Qubit"); + + ir_manip->declareFunction("%Qubit* @__quantum__rt__qubit_allocate()"); + ir_manip->declareFunction("void @__quantum__rt__qubit_release(%Qubit*)"); + ir_manip->declareFunction("void @__quantum__qis__h__body(%Qubit*)"); + + std::string script = R"script( + %qubit = call %Qubit* @__quantum__rt__qubit_allocate() + call void @__quantum__qis__h__body(%Qubit* %qubit) + call void @__quantum__rt__qubit_release(%Qubit* %qubit) + )script"; + + assert(ir_manip->fromBodyString(script)); // Will fail if the IR is invalid +``` + +If we wish to verify the IR, we can print it by using the member function `toString` or by accessing the module directly: + +```c++ + std::cout << ir_manip->toString() << std::endl; + // OR + llvm::errs() << *ir_manip->module() << "\n"; +``` + +## Applying the profile to the IR + +The `IrManipulationTestHelper` contains a member function to run the profile on the IR to transform the module. The default behaviour of this helper function is to run without debug output at a `O0` level to ensure that LLVM does not interfere with the intended test. The optimisation level and debug mode can be changed through the function calls second and third argument, but for the sake of simplicity, we will assume we are using `O0` here: + +```c++ + ir_manip->applyProfile(profile); +``` + +This will run the above generated rule set on the IR we have supplied. At this point, we could print the IR to the screen and use LIT to perform that actually transformation test. However, to keep this test framework self-contained and easy to use, we supply LIT-like functionality. This has the benefit that the tests do not rely on Python and the LIT framework and that the tooling around the test is substantially simpler. + +## Testing the modified IR + +Like before, we can investigate the IR by printing it and as such we could write a test that compared the full IR against an expected string. However, even minor changes in the IR (such as interchanged declarations) would break the test even if the changes would not change the semantics of the code. Instead, the `IrManipulationTestHelper` has another helper function `hasInstructionSequence` which allow us to scan for a sequence of instructions in the body of the main function. In our case, +we expect following two instructions (in order): + +``` + %qubit = inttoptr i64 0 to %Qubit* + tail call void @__quantum__qis__h__body(%Qubit* %qubit) +``` + +The corresponding test code is as follows: + +```c++ + EXPECT_TRUE(ir_manip->hasInstructionSequence({ + "%qubit = inttoptr i64 0 to %Qubit*", + "tail call void @__quantum__qis__h__body(%Qubit* %qubit)" + })); +``` + +By design, the test would pass as long as these two instructions are found (in order) within the full set of instructions of the function body. For instance, a valid IR for this test is + +``` + call void printHelloWorld() + %qubit = inttoptr i64 0 to %Qubit* + %q2 = inttoptr i64 1 to %Qubit* + %q3 = inttoptr i64 2 to %Qubit* + tail call void @__quantum__qis__h__body(%Qubit* %q3) + tail call void @__quantum__qis__h__body(%Qubit* %qubit) + tail call void @__quantum__qis__h__body(%Qubit* %q2) +``` + +but would fail + +``` + tail call void @__quantum__qis__h__body(%Qubit* %qubit) + %qubit = inttoptr i64 0 to %Qubit* +``` + +and + +``` + %qubit = inttoptr i64 0 to %Qubit* +``` + +as the first has the wrong order of the calls and the second is missing one instruction. diff --git a/src/Passes/docs/src/UserGuide/BuildingLibrary.md b/src/Passes/docs/src/UserGuide/BuildingLibrary.md new file mode 100644 index 0000000000..83ea73debc --- /dev/null +++ b/src/Passes/docs/src/UserGuide/BuildingLibrary.md @@ -0,0 +1,149 @@ +# Build guide + +This document will guide you through all the requirements and steps that you need to follow to build the QIR adaptor tool (QAT). The first section of this guide helps you install the tools needed to build QAT. After you have finished with the second section of the guide, you should have the `qat` executable compiled and ready to run. As a part of the third part of this post, we will show you how to build and serve all of the documentation including the user guides, developer guides and API documentation. We will go through the steps of compiling the whole library as well as how to run all the tests suite that has been provided as the fourth part of this document. This part is only relevant if you intend to extend or modify the core codebase. There is no need for it when simply building an extension to QAT without having the need to change anything else in the core library. There is a lot more information about how to create a custom extension within the developers’ section. + +## Prerequisites + +It is necessary for you to have the following tools before you get started on making a new build from this project: + +- C++ compiler +- CMake + +If you are compiling and using the command-line tool, these are necessary tools regardless of whether you plan to develop the library itself. The build configuration is handled by CMake, which informs you if a compiler needs to be installed. + +### On Mac OS X + +Those using Mac OS X can install CMake through the use of a command-line tool called `brew`, as follows: + +```sh +brew install cmake +``` + +It should not even be necessary to install anything else on top of macOS, since the compiler comes preinstalled. There is no need to read the next subsection ([Developer prerequisites](#developer-prerequisites)) if you are not intending to modify the core library and can safely jump to the section [Library Dependencies](#library-dependencies) + +### On Ubuntu 20.04 + +Additionally to CMake, you will also require Clang in order to build Ubuntu 20.04. You can accomplish this by following the steps below: + +```sh +apt install clang-11 cmake +``` + +You can skip straight to [Library Dependencies](#library-dependencies) if you do not intend to work on developing the core library. + +## Developer prerequisites + +Development of the core library requires additional tools. These are used formatting, linting and managing code quality. For this purpose, the following tools and packages are used: + +- Python 3 +- Python packages specified in `requirements.txt` +- clang-format +- clang-tidy + +The installation process varies depending on the platform you use. The following subsections provide details on how to install these tools on each platform. + +### On Mac OS X + +TODO: + +### On Ubuntu 20.04 + +Installing the clang tools on Ubuntu along with Python can be accomplished by running these commands: + +```sh +apt install clang-format-11 clang-tidy-11 +apt install python3 python3-pip +``` + +We recommend that you use version 11 of clang in order to be consistent with the version of LLVM on which the library depends. In general, the code should work with any version of clang. Make sure that the compiler environment variables are defined correctly in order to select the correct version: + +```sh +export CC=clang-11 +export CXX=clang++-11 +``` + +### Common to all platforms + +Last but not least, we install the Python libraries that are required: + +```sh + pip install -r requirements.txt + chmod +x manage +``` + +As a result, the `manage` tool will be available for you to help you make sure your code is high quality. Getting a contribution merged into the code base requires the manage tools CI flow to be successful. Thus, if you plan to contribute you will most likely need to complete this step. + +## Library Dependencies + +The QAT library itself is written in C++ and depends on LLVM for compilation and Google Test for testing purposes. Google test is checked out as a submodule whereas LLVM needs to be installed on the system. To get check out all submodules run + +```sh +git submodule update --init --recursive +``` + +### Installing LLVM on Mac OS X + +TODO: + +### Installing LLVM on Ubuntu 20.04 + +For the installation of LLVM from Ubuntu we use the package manager `apt`. For full run installation, run the following command: + +```sh +apt install llvm-11 lldb-11 llvm-11-dev libllvm11 llvm-11-runtime +``` + +By doing this, we will ensure that CMake can find LLVM and that all headers and libraries used by the QAT library are available. + +# Build instructions for users + +From the root folder in the repository, go to `src/Passes`, then create a build folder `Debug` and use CMake to build the executable: + +```sh +cd Debug +cmake .. +make qat +``` + +then + +```sh +./Source/Apps/qat +``` + +# Building the documentation + +To build the documentation Docker image, run: + +``` +make documentation +``` + +To serve the documentation locally, run: + +``` +make serve-docs +``` + +# Building for developers + +To build the tool, create a new build directory and switch to that directory: + +```sh +mkdir Debug +cd Debug/ +``` + +To build the library, first configure CMake from the build directory + +```sh +cmake .. +``` + +and then make your target + +```sh +make [target] +``` + +The default target is `all`. Other valid targets are the name of the folders in `libs/` found in the passes root. diff --git a/src/Passes/docs/src/UserGuide/IntroductionToProfiles.md b/src/Passes/docs/src/UserGuide/IntroductionToProfiles.md new file mode 100644 index 0000000000..68c5c4b769 --- /dev/null +++ b/src/Passes/docs/src/UserGuide/IntroductionToProfiles.md @@ -0,0 +1,89 @@ +# Introduction to profiles + +In this document we discuss QIR profiles. A QIR profile describes a subset of the generic QIR functionality and conventions. It +is anticipated that most usages of the QIR specification will need to only use a subset of it. These subsets +may further be subject to constraints such as how one allocate or acquire a qubit handle. We refer to such a subset with +constraints as a profile. For instance, it is likely that early versions of quantum hardware will have a limited +set of classical instructions available. With this in mind, the vendor or user of said hardware would define a profile +that only contains a specified subset. One example of such a profile is the base profile, +which only allows function calls and branching, but no arithmetic, classical memory, or classical registers. + +The generation of QIR according to the spec with no constraints would typically be performed by the frontend. A couple +of examples are Q# or OpenQASM 2.0/3.0. However, for the generated QIR to be practical it is necessary to reduce it using a profile +which is compatible with the target platform: + +```text +┌──────────────────────┐ +│ Frontend │ +└──────────────────────┘ + │ + │ QIR + ▼ +┌──────────────────────┐ +│ QIR Adaptor Tool │ <─────── QIR Profile +└──────────────────────┘ + │ + │ Adapted QIR + ▼ +┌──────────────────────┐ +│ Backend │ +└──────────────────────┘ +``` + +As an example, a hardware based quantum platform may only have support for sequential gates with no branching or ability for subroutines. Likewise, some quantum platforms only allow for a single measurement at the end of executing the pipeline of quantum gates. Profiles suppose to express these nuances and restrictions which are absent in the generic QIR. + +## Generic QIR specification + +See [Quantum Intermediate Representation (QIR)](https://github.com/microsoft/qsharp-language/tree/main/Specifications/QIR) + +## Pipeline profile + +This profile assumes a quantum system where qubits and result registers fixed in availability. That is to say, that one target may have 25 qubits and 10 result registers. + +The pipeline profile is the profile with the least classical logic available. It only supports [`call`](https://llvm.org/docs/LangRef.html#call-instruction), [`inttoptr`](https://llvm.org/docs/LangRef.html#inttoptr-to-instruction), 64-bit integers [`i64`](https://llvm.org/docs/LangRef.html#integer-type), qubit ids [`Qubit*`](https://github.com/microsoft/qsharp-language/blob/main/Specifications/QIR/Data-Types.md#opaque-types) and result ids `Result*`. It does not provide a runtime and only intrinsic quantum instructions are available to this profile. This profile is intended for slave-host type infrastructure where a gate pipeline is uploaded to the slave quantum system and executed one or more times. Measurements are always performed at the end of the execution and all available results. This profile only allows for defining a single function that takes no arguments and has no return type. + +Available types +| Typename | Description | +|----------|---| +| Result | Used as pointer type within the ID for constant integers | +| Qubit | Used as pointer type within the ID for constant integers | + +As an example of how these types can be used: + +``` +%0 = Qubit* inttoptr 1 to Qubit* +``` + +which expresses that we store the handle to qubit with ID 1 in the variable `%0`. Result registers are referred to in a similar manner. + +## Base Profile + +The base profile is a slight advancement to the pipeline profile + +Available types +| Typename | | | +|----------|---|---| +| Array | | | +| Result | | | +| Qubit | | | + +Available quantum intrinsic functions +| | | | +|---|---|---| +| | | | +| | | | +| | | | + +Available runtime functions +| | | | +|---|---|---| +| | | | +| | | | +| | | | + +Available IR functionality +| | | | +|---|---|---| +| call | | | +| ret | | | +| | | | diff --git a/src/Passes/docs/src/UserGuide/QuickStart.md b/src/Passes/docs/src/UserGuide/QuickStart.md new file mode 100644 index 0000000000..0f2b72cd2f --- /dev/null +++ b/src/Passes/docs/src/UserGuide/QuickStart.md @@ -0,0 +1,101 @@ +# Quick start + +Before we start, you will need to build the QAT tool. To this end, enter `src/Passes` from the root of the repository and create a new folder `Debug`. Then run `cmake ..` and use `make` to build `qat`: + +```sh +mkdir Debug +cd Debug +cmake .. +make qat +``` + +A more detailed documentation of this step is available in the [build steps section](./BuildingLibrary.md). Once the build has been completed successfully, we will create a QIR in order to have an example code we can apply a profile to. The next step does not need to be completed if you already have a QIR. We will be using the Q# front end to generate the QIR and use the example `SimpleLoop`. However, you are free to choose another example in the `QirExamples` folder and/or another frontend. Go to the folder `./QirExamples/SimpleLoop/QSharpVersion` and type + +```sh +make qir/Example.ll +``` + +This will generate a QIR that will have the path `./QirExamples/SimpleLoop/QSharpVersion/qir/Example.ll` relative to the project root. +By using an application called QAT you can transform the QIR that was generated into a QIR that is tailored to a specific profile. Performing a transformation of the QIR from the `./Debug` folder is done by typing the following commands: + +```sh +./Source/Apps/qat --apply --profile base -S ../QirExamples/SimpleLoop/QSharpVersion/qir/Example.ll +``` + +Validation of QIR profiles is not supported by the tool at the moment. We're working on this feature, and will add the quickstart documentation here when it is available. + +## Example: SimpleLoop + +For the sake of demonstration, we will look at the result of applying the profile to the previous Q# code and its corresponding QIR. However, instead of giving all the 3316 lines of the original QIR, we instead present the frontend code for the QIR. It is always possible to recreate the QIR from the step that was previously explained if you are curious: + +``` +namespace SimpleLoop { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Measurement; + + function Value(r : Result) : Int { + return r == Zero ? 122 | 1337; + } + + @EntryPoint() + operation RunMain() : Int { + let nrIter = 5; + mutable ret = 1; + for _ in 1 .. nrIter { + use q = Qubit(); + H(q); + let r = MResetZ(q); + set ret = Value(r); + } + + return ret; + } +} +``` + +The tool was ran with three options: `--apply`, `--profile base` and `-S`. First, it tells the tool to apply the profile to the QIR so that it can become a profile-specific QIR according to the profile selected. By specifying the value `baseProfile` to the argument `--profile`, we select which profile to use in the tool and the third argument ensures that LLVM IR will be printed to the terminal in a human readable format. The resulting code emitted (omitting declarations) is: + +```ll +; ModuleID = 'QSharpVersion/qir/Example.ll' +source_filename = "QSharpVersion/qir/Example.ll" + +; ... + +define void @SimpleLoop__Main() local_unnamed_addr #0 { +entry: + tail call void @__quantum__qis__h__body(%Qubit* null) + tail call void @__quantum__qis__mz__body(%Qubit* null, %Result* null) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %0 = tail call %Result* @__quantum__rt__result_get_zero() + %1 = tail call i1 @__quantum__rt__result_equal(%Result* null, %Result* %0) + tail call void @__quantum__qis__h__body(%Qubit* null) + tail call void @__quantum__qis__mz__body(%Qubit* null, %Result* nonnull inttoptr (i64 1 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %2 = tail call %Result* @__quantum__rt__result_get_zero() + %3 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 1 to %Result*), %Result* %2) + tail call void @__quantum__qis__h__body(%Qubit* null) + tail call void @__quantum__qis__mz__body(%Qubit* null, %Result* nonnull inttoptr (i64 2 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %4 = tail call %Result* @__quantum__rt__result_get_zero() + %5 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 2 to %Result*), %Result* %4) + tail call void @__quantum__qis__h__body(%Qubit* null) + tail call void @__quantum__qis__mz__body(%Qubit* null, %Result* nonnull inttoptr (i64 3 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %6 = tail call %Result* @__quantum__rt__result_get_zero() + %7 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 3 to %Result*), %Result* %6) + tail call void @__quantum__qis__h__body(%Qubit* null) + tail call void @__quantum__qis__mz__body(%Qubit* null, %Result* nonnull inttoptr (i64 4 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* null) + %8 = tail call %Result* @__quantum__rt__result_get_zero() + %9 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 4 to %Result*), %Result* %8) + %10 = select i1 %9, i64 122, i64 1337 + %11 = tail call %String* @__quantum__rt__int_to_string(i64 %10) + ret void +} + +; … + +attributes #0 = { "EntryPoint" "requiredQubits"="1" } +``` + +A notable feature of the resulting code is that there are no loops, and qubit registers are assigned at compile time, meaning that you can identify each qubit instance by its unique constant integer ID. These are features of the selected profile which does not support neither loops nor dynamic qubit allocation. diff --git a/src/Passes/docs/src/base-profile-transformations.md b/src/Passes/docs/src/base-profile-transformations.md new file mode 100644 index 0000000000..d53ea7913b --- /dev/null +++ b/src/Passes/docs/src/base-profile-transformations.md @@ -0,0 +1,232 @@ +# Proposal: QIR Adaptor Tool Specification + +This document discusses a tool that transforms QIR into a restricted version of the QIR (known as a profile). +We aim to make a specification for a generic tool that allows the user to: + +1. Create or use an existing profile without the need of writing code. +2. Validate that a QIR is compliant with the specific profile. +3. Generate a profile compliant QIR from a generic unconstrained QIR (if possible). + +This document sets out to motivate and demonstrate feasibility of building such a tool. + +## Motivation + +It is anticipated that most usages of the QIR specification will need to only use a subset of it. These subsets +may further be subject to constraints such as how one allocates or acquire a qubit handle. We refer to such a subset with +constraints as a profile. For instance, it is likely that early versions of quantum hardware will have a limited +set of classical instructions available. With this in mind, the vendor or user of said hardware would define a profile +that only contains a specified subset. One example of such a profile is the base profile, +which only allows function calls and branching, but no arithmetic, classical memory, or classical registers. + +The generation of QIR according to the spec with no constraints would typically be performed by the frontend. A couple +of examples are Q# or OpenQASM 2.0/3.0. However, for the generated QIR to be practical it is necessary to reduce it using a profile +which is compatible with the target platform: + +```text +┌──────────────────────┐ +│ │ +│ Frontend │ +│ │ +└──────────────────────┘ + │ + │ + ▼ +┌──────────────────────┐ +│ │ +│ QIR │ +│ │ +└──────────────────────┘ + │ + QIR Adaptor Tool + │ + ▼ +┌──────────────────────┐ +│ │ +│ Restricted QIR │ +│ │ +└──────────────────────┘ +``` + +We propose that such a reduction could be done using the LLVM passes infrastructure to compose a profile +which would map the QIR to a subset of the available instructions with any required constraints. + +## Feasibility Study + +In order to demonstrate feasibility of this proposal, we have built a proof-of-concept prototype based on LLVM passes which allows transformation from a generic QIR into one which does not have support for dynamic qubit allocation. + +This transformation is considered to be the smallest, non-trivial case of QIR transformation we can perform which demonstrates the feasibility of this proposal. + +To demonstrate the feasibility of this proposal, we use Q# as a frontend and will attempt to map the following code + +``` +namespace Feasibility { + open Microsoft.Quantum.Intrinsic; + + @EntryPoint() + operation Run() : Unit { + use qs = Qubit[3]; + for q in 8..10 { + X(qs[q - 8]); + } + } +} +``` + +to the base profile. We will do so using a combination of existing LLVM passes and custom written passes which are specific to the QIR. The above code is interesting as it is not base profile compliant with regards to two aspects: 1) Qubit allocation is not allowed and 2) arithmetic operations are not supported. Using the Q# QIR generator, the `Run` functions body becomes: + +``` +define internal void @Feasibility__Run__body() { +entry: + %qs = call %Array* @__quantum__rt__qubit_allocate_array(i64 3) + call void @__quantum__rt__array_update_alias_count(%Array* %qs, i32 1) + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %q = phi i64 [ 8, %entry ], [ %4, %exiting__1 ] + %0 = icmp sle i64 %q, 10 + br i1 %0, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %1 = sub i64 %q, 8 + %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qs, i64 %1) + %3 = bitcast i8* %2 to %Qubit** + %qubit = load %Qubit*, %Qubit** %3, align 8 + call void @__quantum__qis__x__body(%Qubit* %qubit) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %4 = add i64 %q, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + call void @__quantum__rt__array_update_alias_count(%Array* %qs, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %qs) + ret void +} +``` + +After applying the our demo profile transformation, the QIR is reduced to: + +``` +define void @Feasibility__Run__Interop() local_unnamed_addr #0 { +entry: + call void @__quantum__qis__x__body(%Qubit* null) + call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*)) + ret void +} +``` + +We note that we successfully have eliminated loops, arithmetic operations, dynamic qubit allocation and alias counting - all operations which are not supported by the base profile. + +## Goal + +We envision the tool to work as a stand-alone command line tool which can either validate or generate a QIR in accordance with a given profile. To validate, one would run: + +```language +qat -p profile.yaml --validate unvalidated-qir.ll +``` + +In a similar fashion, generation is performed by adding `--generate` to the command line: + +```language +qat -p profile.yaml --generate qir.ll > qir-profile.ll +``` + +Default behaviour of the tool is that it always validates the generated profile. This behaviour can be disabled by + +```language +qat -p profile.yaml --generate --no-validate qir.ll > qir-profile.ll +``` + +# Profile Specification + +Every profile is specified through a YAML file which defines an object at the top-level. This object must contain the fields `name` and `displayName`: + +```yaml +name: profile-name +displayName: Profile Name +# ... +``` + +Additionally, top level also contains the fields `version` and `mode`. The version refers to the QIR version which forms the basis for the specification and `mode` explains how the profile is defined. +The final two top level fields are lists named `specification` and `generation`. These contains the specification and generation procedure, respectively. + +## Specification + +The default `mode` of specification is by `feature` which means that specification describes the feature set available. Alternatively, one can specify a profile by `limitation`. As an example profile for + +```yaml +name: profile-name +displayName: Profile Name +version: 1.0 +mode: feature +specification: + functions: + - __quantum__qis__toffoli__body + - __quantum__qis__cnot__body + - __quantum__qis__cz__body + - __quantum__qis__h__body + - __quantum__qis__mz__body + - __quantum__qis__reset__body + - __quantum__qis__rx__body + - __quantum__qis__ry__body + - __quantum__qis__rz__body + - __quantum__qis__s__body + - __quantum__qis__s__adj + - __quantum__qis__t__body + - __quantum__qis__t__adj + - __quantum__qis__x__body + - __quantum__qis__y__body + - __quantum__qis__z__body + instructions: + - call + - br + - ret + - inttoptr +# ... +``` + +This specification describes that 16 quantum instructions are available and 4 classical operations of the full QIR spec. Contrary, a specification by `limitation` could be as follows: + +```yaml +name: profile-name +displayName: Profile Name +version: 1.0 +mode: limitation +specification: + functions: + - __quantum__rt__array_update_alias_count + - __quantum__rt__array_update_reference_count + instructions: + - br +# ... +``` + +This profile specifies a system that does not allow reference and alias counting and neither have support for branching, but otherwise has the full QIR vesion 1.0 available. + +## Generation specification + +To achieve the QIR generation in the feasibility section we made use of a number of different passes in order fold constants, unroll loops and map qubit allocations to static allocations. Based on this, we propose that generators are specified by creating a pipeline of LLVM passes to analyse and transform the QIR: + +```yaml +name: profile-name +displayName: Profile Name +# ... +generation: + - passName: loopUnroll + - passName: functionInline + - passName: useStaticQubitAllocation + - passName: eliminateClassicalMemoryUsage + - passName: ignoreCall + config: + names: + - __quantum__rt__array_update_alias_count + - __quantum__rt__array_update_reference_count +``` + +For those passes which are defined specifically for QIR we we allow configuration to be passed to them. This will allow the end-user to fine-tune the behaviour of profile generator. + +# Library outline + +This is a placeholder for describing the outline of the QAT library. The aim is to create a dynamic library where we can add new components that allow to extend the QIR profile generation components with more passes and/or spefication options. diff --git a/src/Passes/docs/src/index.md b/src/Passes/docs/src/index.md new file mode 100644 index 0000000000..7bf4b23d89 --- /dev/null +++ b/src/Passes/docs/src/index.md @@ -0,0 +1,22 @@ +# QIR profile documentation + +Welcome to the QIR Profile SDK, a framework to manipulate QIR into specific profiles. The goal of this framework is to create tools that allow quantum hardware vendors to adapt a generic QIR to their specific hardware profile. + +User guide: + +- [Quick start](UserGuide/QuickStart.md) +- [Building the library](UserGuide/BuildingLibrary.md) +- [Introduction to profiles](UserGuide/IntroductionToProfiles.md) +- Applying a profile (TODO(tfr): Yet to be written) + +Developer guide: + +- [Architecture Overview](DeveloperGuide/ArchitectureOverview.md) +- [Writing a Component](DeveloperGuide/WritingComponent.md) +- [Configuration Library](DeveloperGuide/ConfigurationLibrary.md) +- [Rule based extensions](DeveloperGuide/WritingRuleTests.md) + +Additional developer info: + +- [Code quality](DeveloperGuide/CodeQuality.md) +- [Developer FAQ](DeveloperGuide/DeveloperFAQ.md) diff --git a/src/Passes/docs/yarn.lock b/src/Passes/docs/yarn.lock new file mode 100644 index 0000000000..1518a57e78 --- /dev/null +++ b/src/Passes/docs/yarn.lock @@ -0,0 +1,8011 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== + +"@babel/core@^7.11.0", "@babel/core@^7.8.4": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8" + integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@babel/helper-module-transforms" "^7.15.0" + "@babel/helpers" "^7.14.8" + "@babel/parser" "^7.15.0" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15" + integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== + dependencies: + "@babel/types" "^7.15.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61" + integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191" + integrity sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.0", "@babel/helper-compilation-targets@^7.9.6": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818" + integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.14.5": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz#c9a137a4d137b2d0e2c649acf536d7ba1a76c0f7" + integrity sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-split-export-declaration" "^7.14.5" + +"@babel/helper-create-regexp-features-plugin@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" + integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" + integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== + dependencies: + "@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" + +"@babel/helper-explode-assignable-expression@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645" + integrity sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4" + integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ== + dependencies: + "@babel/helper-get-function-arity" "^7.14.5" + "@babel/template" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-get-function-arity@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815" + integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-hoist-variables@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d" + integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-member-expression-to-functions@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b" + integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg== + dependencies: + "@babel/types" "^7.15.0" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3" + integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08" + integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-simple-access" "^7.14.8" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/helper-optimise-call-expression@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c" + integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-remap-async-to-generator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6" + integrity sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-wrap-function" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4" + integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/helper-simple-access@^7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924" + integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg== + dependencies: + "@babel/types" "^7.14.8" + +"@babel/helper-skip-transparent-expression-wrappers@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4" + integrity sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-split-export-declaration@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a" + integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" + integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + +"@babel/helper-wrap-function@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff" + integrity sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ== + dependencies: + "@babel/helper-function-name" "^7.14.5" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helpers@^7.14.8": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357" + integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g== + dependencies: + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.14.5", "@babel/parser@^7.15.0": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862" + integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e" + integrity sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ== + dependencies: + "@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@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz#7028dc4fa21dc199bbacf98b39bab1267d0eaf9a" + integrity sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw== + dependencies: + "@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@^7.14.5", "@babel/plugin-proposal-class-properties@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" + integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz#158e9e10d449c3849ef3ecde94a03d9f1841b681" + integrity sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg== + dependencies: + "@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@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.14.5.tgz#59bc4dfc1d665b5a6749cf798ff42297ed1b2c1d" + integrity sha512-LYz5nvQcvYeRVjui1Ykn28i+3aUiXwQ/3MGoEy0InTaz1pJo/lAzmIDXX+BQny/oufgHzJ6vnEEiXQ8KZjEVFg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-decorators" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c" + integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76" + integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb" + integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738" + integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6" + integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18" + integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363" + integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g== + dependencies: + "@babel/compat-data" "^7.14.7" + "@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@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" + integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" + integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== + dependencies: + "@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@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d" + integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636" + integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q== + dependencies: + "@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@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8" + integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.14.5.tgz#eafb9c0cbe09c8afeb964ba3a7bbd63945a72f20" + integrity sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.2.0", "@babel/plugin-syntax-jsx@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" + integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-arrow-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" + integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-async-to-generator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" + integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== + dependencies: + "@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@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4" + integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-block-scoping@^7.14.5": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-classes@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz#2a391ffb1e5292710b00f2e2c210e1435e7d449f" + integrity sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A== + dependencies: + "@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@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f" + integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-destructuring@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" + integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a" + integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-duplicate-keys@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954" + integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-exponentiation-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493" + integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-for-of@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb" + integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2" + integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ== + dependencies: + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78" + integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-member-expression-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7" + integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-modules-amd@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7" + integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g== + dependencies: + "@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@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz#3305896e5835f953b5cdb363acd9e8c2219a5281" + integrity sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig== + dependencies: + "@babel/helper-module-transforms" "^7.15.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.14.8" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz#c75342ef8b30dcde4295d3401aae24e65638ed29" + integrity sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA== + dependencies: + "@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@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0" + integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA== + dependencies: + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2" + integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + +"@babel/plugin-transform-new-target@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8" + integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-object-super@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45" + integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.14.5" + +"@babel/plugin-transform-parameters@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3" + integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34" + integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-regenerator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" + integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304" + integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-runtime@^7.11.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3" + integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58" + integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-spread@^7.14.6": + version "7.14.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" + integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + +"@babel/plugin-transform-sticky-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9" + integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-template-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93" + integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typeof-symbol@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4" + integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-escapes@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" + integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e" + integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/preset-env@^7.11.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.0.tgz#e2165bf16594c9c05e52517a194bf6187d6fe464" + integrity sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@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.9" + "@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.7" + "@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.9" + "@babel/plugin-transform-computed-properties" "^7.14.5" + "@babel/plugin-transform-destructuring" "^7.14.7" + "@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.15.0" + "@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.9" + "@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.6" + "@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.15.0" + 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.16.0" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== + dependencies: + "@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/runtime@^7.11.0", "@babel/runtime@^7.8.4": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.0.0", "@babel/template@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" + integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98" + integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@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.15.0" + "@babel/types" "^7.15.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0", "@babel/types@^7.4.4": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" + integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@types/glob@^7.1.1": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" + integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/json-schema@^7.0.5": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "16.6.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.1.tgz#aee62c7b966f55fc66c7b6dfa1d58db2a616da61" + integrity sha512-Sr7BhXEAer9xyGuCN3Ek9eg9xPviCF2gfu9kTfuU2HkTVAMYSDeX40fvpmo72n5nansg3nsBjuQBrsS28r+NUw== + +"@types/q@^1.5.1": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" + integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== + +"@vue/babel-helper-vue-jsx-merge-props@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz#31624a7a505fb14da1d58023725a4c5f270e6a81" + integrity sha512-QOi5OW45e2R20VygMSNhyQHvpdUwQZqGPc748JLGCYEy+yp8fNFNdbNIGAgZmi9e+2JHPd6i6idRuqivyicIkA== + +"@vue/babel-helper-vue-transform-on@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc" + integrity sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA== + +"@vue/babel-plugin-jsx@^1.0.3": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.0.6.tgz#184bf3541ab6efdbe5079ab8b20c19e2af100bfb" + integrity sha512-RzYsvBhzKUmY2YG6LoV+W5PnlnkInq0thh1AzCmewwctAgGN6e9UFon6ZrQQV1CO5G5PeME7MqpB+/vvGg0h4g== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + "@vue/babel-helper-vue-transform-on" "^1.0.2" + camelcase "^6.0.0" + html-tags "^3.1.0" + svg-tags "^1.0.0" + +"@vue/babel-plugin-transform-vue-jsx@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.2.1.tgz#646046c652c2f0242727f34519d917b064041ed7" + integrity sha512-HJuqwACYehQwh1fNT8f4kyzqlNMpBuUK4rSiSES5D4QsYncv5fxFsLyrxFPG2ksO7t5WP+Vgix6tt6yKClwPzA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.2.0" + "@vue/babel-helper-vue-jsx-merge-props" "^1.2.1" + html-tags "^2.0.0" + lodash.kebabcase "^4.1.1" + svg-tags "^1.0.0" + +"@vue/babel-preset-app@^4.1.2": + version "4.5.13" + resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-4.5.13.tgz#cb475321e4c73f7f110dac29a48c2a9cb80afeb6" + integrity sha512-pM7CR3yXB6L8Gfn6EmX7FLNE3+V/15I3o33GkSNsWvgsMp6HVGXKkXgojrcfUUauyL1LZOdvTmu4enU2RePGHw== + dependencies: + "@babel/core" "^7.11.0" + "@babel/helper-compilation-targets" "^7.9.6" + "@babel/helper-module-imports" "^7.8.3" + "@babel/plugin-proposal-class-properties" "^7.8.3" + "@babel/plugin-proposal-decorators" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + "@babel/plugin-transform-runtime" "^7.11.0" + "@babel/preset-env" "^7.11.0" + "@babel/runtime" "^7.11.0" + "@vue/babel-plugin-jsx" "^1.0.3" + "@vue/babel-preset-jsx" "^1.2.4" + babel-plugin-dynamic-import-node "^2.3.3" + core-js "^3.6.5" + core-js-compat "^3.6.5" + semver "^6.1.0" + +"@vue/babel-preset-jsx@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.2.4.tgz#92fea79db6f13b01e80d3a0099e2924bdcbe4e87" + integrity sha512-oRVnmN2a77bYDJzeGSt92AuHXbkIxbf/XXSE3klINnh9AXBmVS1DGa1f0d+dDYpLfsAKElMnqKTQfKn7obcL4w== + dependencies: + "@vue/babel-helper-vue-jsx-merge-props" "^1.2.1" + "@vue/babel-plugin-transform-vue-jsx" "^1.2.1" + "@vue/babel-sugar-composition-api-inject-h" "^1.2.1" + "@vue/babel-sugar-composition-api-render-instance" "^1.2.4" + "@vue/babel-sugar-functional-vue" "^1.2.2" + "@vue/babel-sugar-inject-h" "^1.2.2" + "@vue/babel-sugar-v-model" "^1.2.3" + "@vue/babel-sugar-v-on" "^1.2.3" + +"@vue/babel-sugar-composition-api-inject-h@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.2.1.tgz#05d6e0c432710e37582b2be9a6049b689b6f03eb" + integrity sha512-4B3L5Z2G+7s+9Bwbf+zPIifkFNcKth7fQwekVbnOA3cr3Pq71q71goWr97sk4/yyzH8phfe5ODVzEjX7HU7ItQ== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@vue/babel-sugar-composition-api-render-instance@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.2.4.tgz#e4cbc6997c344fac271785ad7a29325c51d68d19" + integrity sha512-joha4PZznQMsxQYXtR3MnTgCASC9u3zt9KfBxIeuI5g2gscpTsSKRDzWQt4aqNIpx6cv8On7/m6zmmovlNsG7Q== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@vue/babel-sugar-functional-vue@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.2.2.tgz#267a9ac8d787c96edbf03ce3f392c49da9bd2658" + integrity sha512-JvbgGn1bjCLByIAU1VOoepHQ1vFsroSA/QkzdiSs657V79q6OwEWLCQtQnEXD/rLTA8rRit4rMOhFpbjRFm82w== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@vue/babel-sugar-inject-h@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.2.2.tgz#d738d3c893367ec8491dcbb669b000919293e3aa" + integrity sha512-y8vTo00oRkzQTgufeotjCLPAvlhnpSkcHFEp60+LJUwygGcd5Chrpn5480AQp/thrxVm8m2ifAk0LyFel9oCnw== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@vue/babel-sugar-v-model@^1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.2.3.tgz#fa1f29ba51ebf0aa1a6c35fa66d539bc459a18f2" + integrity sha512-A2jxx87mySr/ulAsSSyYE8un6SIH0NWHiLaCWpodPCVOlQVODCaSpiR4+IMsmBr73haG+oeCuSvMOM+ttWUqRQ== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + "@vue/babel-helper-vue-jsx-merge-props" "^1.2.1" + "@vue/babel-plugin-transform-vue-jsx" "^1.2.1" + camelcase "^5.0.0" + html-tags "^2.0.0" + svg-tags "^1.0.0" + +"@vue/babel-sugar-v-on@^1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.2.3.tgz#342367178586a69f392f04bfba32021d02913ada" + integrity sha512-kt12VJdz/37D3N3eglBywV8GStKNUhNrsxChXIV+o0MwVXORYuhDTHJRKPgLJRb/EY3vM2aRFQdxJBp9CLikjw== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + "@vue/babel-plugin-transform-vue-jsx" "^1.2.1" + camelcase "^5.0.0" + +"@vue/component-compiler-utils@^3.1.0": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.2.2.tgz#2f7ed5feed82ff7f0284acc11d525ee7eff22460" + integrity sha512-rAYMLmgMuqJFWAOb3Awjqqv5X3Q3hVr4jH/kgrFJpiU0j3a90tnNBplqbj+snzrgZhC9W128z+dtgMifOiMfJg== + dependencies: + consolidate "^0.15.1" + hash-sum "^1.0.2" + lru-cache "^4.1.2" + merge-source-map "^1.1.0" + postcss "^7.0.36" + postcss-selector-parser "^6.0.2" + source-map "~0.6.1" + vue-template-es2015-compiler "^1.9.0" + optionalDependencies: + prettier "^1.18.2" + +"@vuepress/core@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/core/-/core-1.8.2.tgz#4f5bafc894691bfea4146294a582a129483daf2a" + integrity sha512-lh9BLC06k9s0wxTuWtCkiNj49fkbW87enp0XSrFZHEoyDGSGndQjZmMMErcHc5Hx7nrW1nzc33sPH1NNtJl0hw== + dependencies: + "@babel/core" "^7.8.4" + "@vue/babel-preset-app" "^4.1.2" + "@vuepress/markdown" "1.8.2" + "@vuepress/markdown-loader" "1.8.2" + "@vuepress/plugin-last-updated" "1.8.2" + "@vuepress/plugin-register-components" "1.8.2" + "@vuepress/shared-utils" "1.8.2" + autoprefixer "^9.5.1" + babel-loader "^8.0.4" + cache-loader "^3.0.0" + chokidar "^2.0.3" + connect-history-api-fallback "^1.5.0" + copy-webpack-plugin "^5.0.2" + core-js "^3.6.4" + cross-spawn "^6.0.5" + css-loader "^2.1.1" + file-loader "^3.0.1" + js-yaml "^3.13.1" + lru-cache "^5.1.1" + mini-css-extract-plugin "0.6.0" + optimize-css-assets-webpack-plugin "^5.0.1" + portfinder "^1.0.13" + postcss-loader "^3.0.0" + postcss-safe-parser "^4.0.1" + toml "^3.0.0" + url-loader "^1.0.1" + vue "^2.6.10" + vue-loader "^15.7.1" + vue-router "^3.4.5" + vue-server-renderer "^2.6.10" + vue-template-compiler "^2.6.10" + vuepress-html-webpack-plugin "^3.2.0" + vuepress-plugin-container "^2.0.2" + webpack "^4.8.1" + webpack-chain "^6.0.0" + webpack-dev-server "^3.5.1" + webpack-merge "^4.1.2" + webpackbar "3.2.0" + +"@vuepress/markdown-loader@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/markdown-loader/-/markdown-loader-1.8.2.tgz#b2a58291a967f2bbe0af6e58f9542f5911879233" + integrity sha512-mWzFXikCUcAN/chpKkqZpRYKdo0312hMv8cBea2hvrJYV6y4ODB066XKvXN8JwOcxuCjxWYJkhWGr+pXq1oTtw== + dependencies: + "@vuepress/markdown" "1.8.2" + loader-utils "^1.1.0" + lru-cache "^5.1.1" + +"@vuepress/markdown@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/markdown/-/markdown-1.8.2.tgz#50ea5a1962591a436b26d1aa2b111df37eb9ea8a" + integrity sha512-zznBHVqW+iBkznF/BO/GY9RFu53khyl0Ey0PnGqvwCJpRLNan6y5EXgYumtjw2GSYn5nDTTALYxtyNBdz64PKg== + dependencies: + "@vuepress/shared-utils" "1.8.2" + markdown-it "^8.4.1" + markdown-it-anchor "^5.0.2" + markdown-it-chain "^1.3.0" + markdown-it-emoji "^1.4.0" + markdown-it-table-of-contents "^0.4.0" + prismjs "^1.13.0" + +"@vuepress/plugin-active-header-links@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.8.2.tgz#0cb9b29c826dd97d35357a9b09c962ef782cb793" + integrity sha512-JmXAQg8D7J8mcKe2Ue3BZ9dOCzJMJXP4Cnkkc/IrqfDg0ET0l96gYWZohCqlvRIWt4f0VPiFAO4FLYrW+hko+g== + dependencies: + lodash.debounce "^4.0.8" + +"@vuepress/plugin-last-updated@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/plugin-last-updated/-/plugin-last-updated-1.8.2.tgz#7ce689f8d5050cf0213949bc2e5aa879c09ff4b1" + integrity sha512-pYIRZi52huO9b6HY3JQNPKNERCLzMHejjBRt9ekdnJ1xhLs4MmRvt37BoXjI/qzvXkYtr7nmGgnKThNBVRTZuA== + dependencies: + cross-spawn "^6.0.5" + +"@vuepress/plugin-nprogress@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/plugin-nprogress/-/plugin-nprogress-1.8.2.tgz#dc6c082925420c8c59ecb7fc2d4a9401f6d4664a" + integrity sha512-3TOBee2NM3WLr1tdjDTGfrAMggjN+OlEPyKyv8FqThsVkDYhw48O3HwqlThp9KX7UbL3ExxIFBwWRFLC+kYrdw== + dependencies: + nprogress "^0.2.0" + +"@vuepress/plugin-register-components@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/plugin-register-components/-/plugin-register-components-1.8.2.tgz#2fb45a68b0a1efb8822670d95c3b231a2d0eb74d" + integrity sha512-6SUq3nHFMEh9qKFnjA8QnrNxj0kLs7+Gspq1OBU8vtu0NQmSvLFZVaMV7pzT/9zN2nO5Pld5qhsUJv1g71MrEA== + dependencies: + "@vuepress/shared-utils" "1.8.2" + +"@vuepress/plugin-search@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/plugin-search/-/plugin-search-1.8.2.tgz#74b92f663acf6b4560e15dc0442a84c4e874e206" + integrity sha512-JrSJr9o0Kar14lVtZ4wfw39pplxvvMh8vDBD9oW09a+6Zi/4bySPGdcdaqdqGW+OHSiZNvG+6uyfKSBBBqF6PA== + +"@vuepress/shared-utils@1.8.2", "@vuepress/shared-utils@^1.2.0": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/shared-utils/-/shared-utils-1.8.2.tgz#5ec1601f2196aca34ad82eed7c9be2d7948f705b" + integrity sha512-6kGubc7iBDWruEBUU7yR+sQ++SOhMuvKWvWeTZJKRZedthycdzYz7QVpua0FaZSAJm5/dIt8ymU4WQvxTtZgTQ== + dependencies: + chalk "^2.3.2" + escape-html "^1.0.3" + fs-extra "^7.0.1" + globby "^9.2.0" + gray-matter "^4.0.1" + hash-sum "^1.0.2" + semver "^6.0.0" + toml "^3.0.0" + upath "^1.1.0" + +"@vuepress/theme-default@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@vuepress/theme-default/-/theme-default-1.8.2.tgz#7f474036c752c1f9801b83f68f5c70c092b182b4" + integrity sha512-rE7M1rs3n2xp4a/GrweO8EGwqFn3EA5gnFWdVmVIHyr7C1nix+EqjpPQF1SVWNnIrDdQuCw38PqS+oND1K2vYw== + dependencies: + "@vuepress/plugin-active-header-links" "1.8.2" + "@vuepress/plugin-nprogress" "1.8.2" + "@vuepress/plugin-search" "1.8.2" + docsearch.js "^2.5.2" + lodash "^4.17.15" + stylus "^0.54.8" + stylus-loader "^3.0.2" + vuepress-plugin-container "^2.0.2" + vuepress-plugin-smooth-scroll "^0.0.3" + +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== + +"@webassemblyjs/helper-api-error@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== + +"@webassemblyjs/helper-buffer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== + +"@webassemblyjs/helper-code-frame@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== + dependencies: + "@webassemblyjs/wast-printer" "1.9.0" + +"@webassemblyjs/helper-fsm@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== + +"@webassemblyjs/helper-module-context@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== + dependencies: + "@webassemblyjs/ast" "1.9.0" + +"@webassemblyjs/helper-wasm-bytecode@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== + +"@webassemblyjs/helper-wasm-section@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== + +"@webassemblyjs/wasm-edit@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== + dependencies: + "@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@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn@^6.4.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +agentkeepalive@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef" + integrity sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8= + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +algoliasearch@^3.24.5: + version "3.35.1" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-3.35.1.tgz#297d15f534a3507cab2f5dfb996019cac7568f0c" + integrity sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ== + dependencies: + agentkeepalive "^2.2.0" + debug "^2.6.9" + envify "^4.0.0" + es6-promise "^4.1.0" + events "^1.1.0" + foreach "^2.0.5" + global "^4.3.2" + inherits "^2.0.1" + isarray "^2.0.1" + load-script "^1.0.0" + object-keys "^1.0.11" + querystring-es3 "^0.2.1" + reduce "^1.0.1" + semver "^5.1.0" + tunnel-agent "^0.6.0" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-escapes@^4.1.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1, array-union@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autocomplete.js@0.36.0: + version "0.36.0" + resolved "https://registry.yarnpkg.com/autocomplete.js/-/autocomplete.js-0.36.0.tgz#94fe775fe64b6cd42e622d076dc7fd26bedd837b" + integrity sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q== + dependencies: + immediate "^3.2.3" + +autoprefixer@^9.5.1: + version "9.8.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + dependencies: + 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" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +babel-loader@^8.0.4: + version "8.2.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" + integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^1.4.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-polyfill-corejs2@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" + integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.2" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz#68cb81316b0e8d9d721a92e0009ec6ecd4cd2ca9" + integrity sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.14.0" + +babel-plugin-polyfill-regenerator@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" + integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.0.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + 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" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bluebird@^3.1.1, bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + 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" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + 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@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +boxen@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" + integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^3.0.0" + cli-boxes "^2.2.0" + string-width "^4.1.0" + term-size "^2.1.0" + type-fest "^0.8.1" + widest-line "^3.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + 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" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + 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@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + 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" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.16.7: + version "4.16.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.7.tgz#108b0d1ef33c4af1b587c54f390e7041178e4335" + integrity sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA== + dependencies: + caniuse-lite "^1.0.30001248" + colorette "^1.2.2" + electron-to-chromium "^1.3.793" + escalade "^3.1.1" + node-releases "^1.1.73" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-json@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-json/-/buffer-json-2.0.0.tgz#f73e13b1e42f196fe2fd67d001c7d7107edd7c23" + integrity sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cac@^6.5.6: + version "6.7.3" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.3.tgz#10410b8611677990cc2e3c8b576d471c1d71b768" + integrity sha512-ECVqVZh74qgSuZG9YOt2OJPI3wGcf+EwwuF/XIOYqZBD0KZYLtgPWqFPxmDPQ6joxI1nOlvVgRV6VT53Ooyocg== + +cacache@^12.0.2, cacache@^12.0.3: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + 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" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + 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" + +cache-loader@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cache-loader/-/cache-loader-3.0.1.tgz#cee6cf4b3cdc7c610905b26bad6c2fc439c821af" + integrity sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw== + dependencies: + buffer-json "^2.0.0" + find-cache-dir "^2.1.0" + loader-utils "^1.2.3" + mkdirp "^0.5.1" + neo-async "^2.6.1" + schema-utils "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase@^5.0.0, camelcase@^5.2.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001248: + version "1.0.30001251" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz#6853a606ec50893115db660f82c094d18f096d85" + integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^2.0.3, chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + 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" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.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" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +ci-info@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" + integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@4.2.x: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + dependencies: + source-map "~0.6.0" + +cli-boxes@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" + integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorette@^1.2.1, colorette@^1.2.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af" + integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@2.17.x: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@~2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + 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" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +connect-history-api-fallback@^1.5.0, connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +consola@^2.6.0: + version "2.15.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" + integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +consolidate@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== + dependencies: + bluebird "^3.1.1" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + 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" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-webpack-plugin@^5.0.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz#8a889e1dcafa6c91c6cd4be1ad158f1d3823bae2" + integrity sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ== + dependencies: + cacache "^12.0.3" + find-cache-dir "^2.1.0" + glob-parent "^3.1.0" + globby "^7.1.1" + is-glob "^4.0.1" + loader-utils "^1.2.3" + minimatch "^3.0.4" + normalize-path "^3.0.0" + p-limit "^2.2.1" + schema-utils "^1.0.0" + serialize-javascript "^4.0.0" + webpack-log "^2.0.0" + +core-js-compat@^3.14.0, core-js-compat@^3.16.0, core-js-compat@^3.6.5: + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.2.tgz#442ef1d933ca6fc80859bd5a1db7a3ba716aaf56" + integrity sha512-4lUshXtBXsdmp8cDWh6KKiHUg40AjiuPD3bOWkNVsr1xkAhpUqCjaZ8lB1bKx9Gb5fXcbRbFJ4f4qpRIRTuJqQ== + dependencies: + browserslist "^4.16.7" + semver "7.0.0" + +core-js@^3.6.4, core-js@^3.6.5: + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.2.tgz#3f485822889c7fc48ef463e35be5cc2a4a01a1f4" + integrity sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + 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@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + 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@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + 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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-loader@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" + integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== + dependencies: + camelcase "^5.2.0" + icss-utils "^4.1.0" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.14" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^2.0.6" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^2.0.0" + postcss-value-parser "^3.3.0" + schema-utils "^1.0.0" + +css-parse@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" + integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= + dependencies: + css "^2.0.0" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +css-what@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== + +css@^2.0.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff" + integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ== + dependencies: + 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@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.11" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99" + integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.8" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.1, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + 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-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deepmerge@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" + integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@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" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^2.0.0, dir-glob@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" + integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== + dependencies: + path-type "^3.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +docsearch.js@^2.5.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/docsearch.js/-/docsearch.js-2.6.3.tgz#57cb4600d3b6553c677e7cbbe6a734593e38625d" + integrity sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A== + dependencies: + algoliasearch "^3.24.5" + autocomplete.js "0.36.0" + hogan.js "^3.0.2" + request "^2.87.0" + stack-utils "^1.0.1" + to-factory "^1.0.0" + zepto "^1.2.0" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" + integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA== + dependencies: + domelementtype "^2.2.0" + +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442" + integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.793: + version "1.3.810" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.810.tgz#23e340507e13e48debdb7445d2f8fbfab681c4df" + integrity sha512-NteznMlGtkIZCJNM2X6AVm3oMqWAdq7TjqagZhmVLPwd9mtrIq+rRxGHerjFAOFIqQJYQUMT72ncd/lVcH1cOw== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + 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" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" + integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +envify@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" + integrity sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw== + dependencies: + esprima "^4.0.0" + through "~2.3.4" + +envinfo@^7.2.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +errno@^0.1.3, errno@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.2, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: + version "1.18.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19" + integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA== + dependencies: + 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" + internal-slot "^1.0.3" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.11.0" + 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@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-promise@^4.1.0: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-html@^1.0.3, escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + +events@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + 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" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + 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" + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + 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" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + 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" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^2.2.6: + version "2.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" + integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.1.2" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.3" + micromatch "^3.1.10" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +figgy-pudding@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-loader@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" + integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== + dependencies: + loader-utils "^1.0.2" + schema-utils "^1.0.0" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + 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" + +find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-cache-dir@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" + integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + +glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + 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" + +global-dirs@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" + integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== + dependencies: + ini "1.3.7" + +global@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +globby@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" + integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^1.0.2" + dir-glob "^2.2.2" + fast-glob "^2.2.6" + glob "^7.1.3" + ignore "^4.0.3" + pify "^4.0.1" + slash "^2.0.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +gray-matter@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" + integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== + dependencies: + js-yaml "^3.13.1" + kind-of "^6.0.2" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +has@^1.0.0, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash-sum@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04" + integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ= + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.x, he@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hogan.js@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/hogan.js/-/hogan.js-3.0.2.tgz#4cd9e1abd4294146e7679e41d7898732b02c7bfd" + integrity sha1-TNnhq9QpQUbnZ55B14mHMrAse/0= + dependencies: + mkdirp "0.3.0" + nopt "1.0.10" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-entities@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== + +html-minifier@^3.2.3: + version "3.5.21" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" + integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== + dependencies: + camel-case "3.0.x" + clean-css "4.2.x" + commander "2.17.x" + he "1.2.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.4.x" + +html-tags@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" + integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-parser-js@>=0.5.1: + version "0.5.3" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" + integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + +icss-utils@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +ignore@^4.0.3: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + 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@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" + integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-npm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" + integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-path-inside@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4, is-regex@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-string@^1.0.5, is-string@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +javascript-stringify@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3" + integrity sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM= + +javascript-stringify@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79" + integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +last-call-webpack-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" + integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== + dependencies: + lodash "^4.17.5" + webpack-sources "^1.1.0" + +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +linkify-it@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" + integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== + dependencies: + uc.micro "^1.0.1" + +load-script@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" + integrity sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ= + +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.template@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.5: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.6.8: + version "1.7.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" + integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^4.1.2: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-it-anchor@^5.0.2: + version "5.3.0" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz#d549acd64856a8ecd1bea58365ef385effbac744" + integrity sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA== + +markdown-it-chain@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz#ccf6fe86c10266bafb4e547380dfd7f277cc17bc" + integrity sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ== + dependencies: + webpack-chain "^4.9.0" + +markdown-it-container@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-it-container/-/markdown-it-container-2.0.0.tgz#0019b43fd02eefece2f1960a2895fba81a404695" + integrity sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU= + +markdown-it-emoji@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc" + integrity sha1-m+4OmpkKljupbfaYDE/dsF37Tcw= + +markdown-it-table-of-contents@^0.4.0: + version "0.4.4" + resolved "https://registry.yarnpkg.com/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz#3dc7ce8b8fc17e5981c77cc398d1782319f37fbc" + integrity sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw== + +markdown-it@^8.4.1: + version "8.4.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" + integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-source-map@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" + integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== + dependencies: + source-map "^0.6.1" + +merge2@^1.2.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + 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" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.49.0, "mime-db@>= 1.43.0 < 2": + version "1.49.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" + integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.32" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" + integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== + dependencies: + mime-db "1.49.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.0.3, mime@^2.4.4: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +mini-css-extract-plugin@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz#a3f13372d6fcde912f3ee4cd039665704801e3b9" + integrity sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw== + dependencies: + loader-utils "^1.1.0" + normalize-url "^2.0.1" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + 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@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= + +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + 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" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + 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" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.5.0, neo-async@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + 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" + +node-releases@^1.1.73: + version "1.1.75" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe" + integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw== + +nopt@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= + dependencies: + abbrev "1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= + +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +nth-check@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" + integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== + dependencies: + boolbase "^1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.0, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" + integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" + integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +opencollective-postinstall@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +optimize-css-assets-webpack-plugin@^5.0.1: + version "5.0.8" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.8.tgz#cbccdcf5a6ef61d4f8cc78cf083a67446e5f402a" + integrity sha512-mgFS1JdOtEGzD8l+EuISqL57cKO+We9GcoiQEmdCWRqqck+FGNmYJtx9qfAPzEz+lRrlThWMuGDaRkI/yWNx/Q== + dependencies: + cssnano "^4.1.10" + last-call-webpack-plugin "^3.0.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= + dependencies: + no-case "^2.2.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + 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@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + 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@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +portfinder@^1.0.13, portfinder@^1.0.26: + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-calc@^7.0.1: + version "7.0.5" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e" + integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg== + dependencies: + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-load-config@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" + integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== + dependencies: + cosmiconfig "^5.0.0" + import-cwd "^2.0.0" + +postcss-loader@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + 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" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + 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" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" + integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + postcss-value-parser "^3.3.1" + +postcss-modules-scope@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" + integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" + integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^7.0.6" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-safe-parser@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" + integrity sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g== + dependencies: + postcss "^7.0.26" + +postcss-selector-parser@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== + dependencies: + dot-prop "^5.2.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: + version "6.0.6" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-svgo@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e" + integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.36" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.36.tgz#056f8cffa939662a8f5905950c07d5285644dfcb" + integrity sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +prettier@^1.18.2: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + +pretty-error@^2.0.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" + integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== + dependencies: + lodash "^4.17.20" + renderkid "^2.0.4" + +pretty-time@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" + integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== + +prismjs@^1.13.0: + version "1.24.1" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.1.tgz#c4d7895c4d6500289482fa8936d9cdd192684036" + integrity sha512-mNPsedLuk90RVJioIky8ANZEwYm5w9LcvCXrxHlwf4fNVSn8jEipMybMkWUyyF0JhnC+C4VcOVSBuHRKs1L5Ow== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +proxy-addr@~2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + 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" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +pupa@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== + dependencies: + escape-goat "^2.0.0" + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0, querystring-es3@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + 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" + +readable-stream@^3.0.6, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reduce@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce/-/reduce-1.0.2.tgz#0cd680ad3ffe0b060e57a5c68bdfce37168d361b" + integrity sha512-xX7Fxke/oHO5IfZSk77lvPa/7bjMh9BuCk4OOoX5XTXrM7s0Z+MkPfSDfz0q7r91BhhGSs8gii/VEN/7zhCPpQ== + dependencies: + object-keys "^1.1.0" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpu-core@^4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" + integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== + dependencies: + 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" + +registry-auth-token@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.6.4: + version "0.6.9" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6" + integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +renderkid@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" + integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^3.0.1" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request@^2.87.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.14.2, resolve@^1.2.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +section-matter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" + integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== + dependencies: + extend-shallow "^2.0.1" + kind-of "^6.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.8: + version "1.10.11" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9" + integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA== + dependencies: + node-forge "^0.10.0" + +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.1.0, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + 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" + +serialize-javascript@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea" + integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + 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" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +smoothscroll-polyfill@^0.4.3: + version "0.4.4" + resolved "https://registry.yarnpkg.com/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.4.tgz#3a259131dc6930e6ca80003e1cb03b603b69abf8" + integrity sha512-TK5ZA9U5RqCwMpfoMq/l1mrH0JAR7y7KRvOBx0n2869aLxch+gT9GhN3yUfjiw+d/DiF1mKo14+hd62JyMmoBg== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + 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" + +sockjs-client@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6" + integrity sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ== + dependencies: + 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" + +sockjs@^0.3.21: + version "0.3.21" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" + integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== + dependencies: + faye-websocket "^0.11.3" + uuid "^3.4.0" + websocket-driver "^0.7.4" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + 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@~0.5.12: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + 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" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" + integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== + dependencies: + figgy-pudding "^3.5.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-utils@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" + integrity sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== + dependencies: + escape-string-regexp "^2.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +std-env@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.3.0.tgz#66d4a4a4d5224242ed8e43f5d65cfa9095216eee" + integrity sha512-4qT5B45+Kjef2Z6pE0BkskzsH0GO7GrND0wGlTM1ioUe3v0dGYx9ZJH0Aro/YyA8fqQ5EyIKDRjZojJYMFTflw== + dependencies: + ci-info "^3.0.0" + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + 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@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.0.0, string-width@^4.1.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-bom-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +stylus-loader@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-3.0.2.tgz#27a706420b05a38e038e7cacb153578d450513c6" + integrity sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA== + dependencies: + loader-utils "^1.0.2" + lodash.clonedeep "^4.5.0" + when "~3.6.x" + +stylus@^0.54.8: + version "0.54.8" + resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" + integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg== + dependencies: + css-parse "~2.0.0" + debug "~3.1.0" + glob "^7.1.6" + mkdirp "~1.0.4" + safer-buffer "^2.1.2" + sax "~1.2.4" + semver "^6.3.0" + source-map "^0.7.3" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + +svgo@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + 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" + +tapable@^1.0.0, tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +term-size@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== + +terser-webpack-plugin@^1.4.3: + version "1.4.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" + integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== + dependencies: + 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" + +terser@^4.1.2: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-factory@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-factory/-/to-factory-1.0.0.tgz#8738af8bd97120ad1d4047972ada5563bf9479b1" + integrity sha1-hzivi9lxIK0dQEeXKtpVY7+UebE= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +toml@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== + +toposort@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" + integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@3.4.x: + version "3.4.10" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" + integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== + dependencies: + commander "~2.19.0" + source-map "~0.6.1" + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + 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@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.0, upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-notifier@^4.0.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== + dependencies: + boxen "^4.2.0" + chalk "^3.0.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.3.1" + is-npm "^4.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + pupa "^2.0.1" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8" + integrity sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg== + dependencies: + loader-utils "^1.1.0" + mime "^2.0.3" + schema-utils "^1.0.0" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-parse@^1.4.3, url-parse@^1.5.1: + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +vue-hot-reload-api@^2.3.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2" + integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog== + +vue-loader@^15.7.1: + version "15.9.8" + resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.8.tgz#4b0f602afaf66a996be1e534fb9609dc4ab10e61" + integrity sha512-GwSkxPrihfLR69/dSV3+5CdMQ0D+jXg8Ma1S4nQXKJAznYFX14vHdc/NetQc34Dw+rBbIJyP7JOuVb9Fhprvog== + dependencies: + "@vue/component-compiler-utils" "^3.1.0" + hash-sum "^1.0.2" + loader-utils "^1.1.0" + vue-hot-reload-api "^2.3.0" + vue-style-loader "^4.1.0" + +vue-router@^3.4.5: + version "3.5.2" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.5.2.tgz#5f55e3f251970e36c3e8d88a7cd2d67a350ade5c" + integrity sha512-807gn82hTnjCYGrnF3eNmIw/dk7/GE4B5h69BlyCK9KHASwSloD1Sjcn06zg9fVG4fYH2DrsNBZkpLtb25WtaQ== + +vue-server-renderer@^2.6.10: + version "2.6.14" + resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.14.tgz#c8bffff152df6b47b858818ef8d524d2fc351654" + integrity sha512-HifYRa/LW7cKywg9gd4ZtvtRuBlstQBao5ZCWlg40fyB4OPoGfEXAzxb0emSLv4pBDOHYx0UjpqvxpiQFEuoLA== + dependencies: + chalk "^1.1.3" + hash-sum "^1.0.2" + he "^1.1.0" + lodash.template "^4.5.0" + lodash.uniq "^4.5.0" + resolve "^1.2.0" + serialize-javascript "^3.1.0" + source-map "0.5.6" + +vue-style-loader@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz#6d55863a51fa757ab24e89d9371465072aa7bc35" + integrity sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg== + dependencies: + hash-sum "^1.0.2" + loader-utils "^1.0.2" + +vue-template-compiler@^2.6.10: + version "2.6.14" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz#a2f0e7d985670d42c9c9ee0d044fed7690f4f763" + integrity sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g== + dependencies: + de-indent "^1.0.2" + he "^1.1.0" + +vue-template-es2015-compiler@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" + integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== + +vue@^2.6.10: + version "2.6.14" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235" + integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ== + +vuepress-html-webpack-plugin@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/vuepress-html-webpack-plugin/-/vuepress-html-webpack-plugin-3.2.0.tgz#219be272ad510faa8750d2d4e70fd028bfd1c16e" + integrity sha512-BebAEl1BmWlro3+VyDhIOCY6Gef2MCBllEVAP3NUAtMguiyOwo/dClbwJ167WYmcxHJKLl7b0Chr9H7fpn1d0A== + dependencies: + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + tapable "^1.0.0" + toposort "^1.0.0" + util.promisify "1.0.0" + +vuepress-plugin-container@^2.0.2: + version "2.1.5" + resolved "https://registry.yarnpkg.com/vuepress-plugin-container/-/vuepress-plugin-container-2.1.5.tgz#37fff05662fedbd63ffd3a5463b2592c7a7f3133" + integrity sha512-TQrDX/v+WHOihj3jpilVnjXu9RcTm6m8tzljNJwYhxnJUW0WWQ0hFLcDTqTBwgKIFdEiSxVOmYE+bJX/sq46MA== + dependencies: + "@vuepress/shared-utils" "^1.2.0" + markdown-it-container "^2.0.0" + +vuepress-plugin-smooth-scroll@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz#6eff2d4c186cca917cc9f7df2b0af7de7c8c6438" + integrity sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg== + dependencies: + smoothscroll-polyfill "^0.4.3" + +vuepress@^1.5.3: + version "1.8.2" + resolved "https://registry.yarnpkg.com/vuepress/-/vuepress-1.8.2.tgz#97e8bf979630611fc7b621fc4cc35b798ee5e847" + integrity sha512-BU1lUDwsA3ghf7a9ga4dsf0iTc++Z/l7BR1kUagHWVBHw7HNRgRDfAZBDDQXhllMILVToIxaTifpne9mSi94OA== + dependencies: + "@vuepress/core" "1.8.2" + "@vuepress/theme-default" "1.8.2" + cac "^6.5.6" + envinfo "^7.2.0" + opencollective-postinstall "^2.0.2" + update-notifier "^4.0.0" + +watchpack-chokidar2@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" + integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== + dependencies: + chokidar "^2.1.8" + +watchpack@^1.7.4: + version "1.7.5" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" + integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== + dependencies: + graceful-fs "^4.1.2" + neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.1" + watchpack-chokidar2 "^2.0.1" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-chain@^4.9.0: + version "4.12.1" + resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.12.1.tgz#6c8439bbb2ab550952d60e1ea9319141906c02a6" + integrity sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ== + dependencies: + deepmerge "^1.5.2" + javascript-stringify "^1.6.0" + +webpack-chain@^6.0.0: + version "6.5.1" + resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-6.5.1.tgz#4f27284cbbb637e3c8fbdef43eef588d4d861206" + integrity sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA== + dependencies: + deepmerge "^1.5.2" + javascript-stringify "^2.0.1" + +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.5.1: + version "3.11.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" + integrity sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ== + dependencies: + 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" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@^4.1.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.8.1: + version "4.46.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" + integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== + dependencies: + "@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.5.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" + +webpackbar@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-3.2.0.tgz#bdaad103fad11a4e612500e72aaae98b08ba493f" + integrity sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw== + dependencies: + ansi-escapes "^4.1.0" + chalk "^2.4.1" + consola "^2.6.0" + figures "^3.0.0" + pretty-time "^1.1.0" + std-env "^2.2.1" + text-table "^0.2.0" + wrap-ansi "^5.1.0" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +when@~3.6.x: + version "3.6.4" + resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" + integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404= + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + 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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + 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" + +zepto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/zepto/-/zepto-1.2.0.tgz#e127bd9e66fd846be5eab48c1394882f7c0e4f98" + integrity sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g= diff --git a/src/Passes/doxygen.cfg b/src/Passes/doxygen.cfg new file mode 100644 index 0000000000..f626661f99 --- /dev/null +++ b/src/Passes/doxygen.cfg @@ -0,0 +1,2618 @@ +# Doxyfile 1.9.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "QIR Adaptor Tool" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = Doxygen/ + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = Source/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = Source/ + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = Source/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /