浏览代码

Add Monaco editor

bdbai 3 年之前
父节点
当前提交
880920bf84

+ 13 - 2
Maple.App/App.cpp

@@ -1,9 +1,11 @@
 #include "pch.h"
 #include <winsock2.h>
+#include <chrono>
 
 #include "App.h"
 #include "MainPage.h"
 #include "EditPage.h"
+#include "MonacoEditPage.h"
 
 using namespace winrt;
 using namespace Windows::ApplicationModel;
@@ -116,14 +118,23 @@ void App::OnLaunched(LaunchActivatedEventArgs const& e)
 /// <param name="e">Details about the suspend request.</param>
 fire_and_forget App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e)
 {
+    using namespace std::literals::chrono_literals;
     // Save application state and stop any background activity
     const auto& saveModifiedContent = EditPage::SaveModifiedContent;
-    if (saveModifiedContent == nullptr) {
+    const auto& saveMonacoModifiedContent = MonacoEditPage::SaveModifiedContent;
+    if (saveModifiedContent == nullptr && saveMonacoModifiedContent) {
         co_return;
     }
 
     const auto& def = e.SuspendingOperation().GetDeferral();
-    co_await saveModifiedContent();
+    if (saveModifiedContent != nullptr) {
+        co_await saveModifiedContent();
+    }
+    if (saveMonacoModifiedContent != nullptr)
+    {
+        co_await saveMonacoModifiedContent();
+        co_await 1500ms;
+    }
     def.Complete();
 }
 

+ 17 - 4
Maple.App/App.xaml

@@ -2,10 +2,23 @@
     x:Class="Maple_App.App"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="using:Maple_App">
+    xmlns:local="using:Maple_App"
+    xmlns:controls="using:Microsoft.UI.Xaml.Controls">
     <Application.Resources>
-        <ResourceDictionary>
-            <Color x:Key="SystemAccentColor">#2ebe5a</Color>
-        </ResourceDictionary>
+        <controls:XamlControlsResources>
+            <controls:XamlControlsResources.MergedDictionaries>
+                <ResourceDictionary>
+                    <Color x:Key="SystemAccentColor">#2fc751</Color>
+                    <Color x:Key="SystemAccentColorLight1">#33cf5a</Color>
+                    <Color x:Key="SystemAccentColorLight2">#5fda87</Color>
+                    <Color x:Key="SystemAccentColorLight3">#8ed7bd</Color>
+                    <Color x:Key="SystemAccentColorDark1">#219349</Color>
+                    <Color x:Key="SystemAccentColorDark2">#135f3b</Color>
+                    <Color x:Key="SystemAccentColorDark3">#0c4432</Color>
+                </ResourceDictionary>
+            </controls:XamlControlsResources.MergedDictionaries>
+        </controls:XamlControlsResources>
+
+        <!--<Color x:Key="SystemAccentColor">#2ebe5a </Color>-->
     </Application.Resources>
 </Application>

+ 5 - 2
Maple.App/MainPage.cpp

@@ -222,7 +222,7 @@ namespace winrt::Maple_App::implementation
         }
 
         if (ConfigListView().SelectedItem() == item) {
-            ConfigListView().SelectedIndex(!ConfigListView().SelectedIndex());
+            ConfigListView().SelectedIndex(ConfigListView().SelectedIndex() == 0 ? 1 : 0);
         }
         configItems.RemoveAt(index);
         co_await item.Delete();
@@ -342,7 +342,7 @@ namespace winrt::Maple_App::implementation
     void MainPage::ConfigListView_SelectionChanged(IInspectable const&, SelectionChangedEventArgs const& e)
     {
         const auto& item = e.AddedItems().First().Current();
-        auto targetPage = xaml_typename<EditPage>();
+        auto targetPage = xaml_typename<MonacoEditPage>();
         const auto& config = item.try_as<Maple_App::ConfigViewModel>();
         if (config != nullptr) {
             const auto ext = getNormalizedExtentionFromPath(config.Name());
@@ -356,7 +356,10 @@ namespace winrt::Maple_App::implementation
                 targetPage = xaml_typename<CertPage>();
             }
         }
+        if (targetPage.Name != xaml_typename<MonacoEditPage>().Name)
+        {
         MainContentFrame().BackStack().Clear();
+        }
         MainContentFrame().Navigate(targetPage, item);
     }
 

+ 7 - 2
Maple.App/MainPage.xaml

@@ -8,6 +8,7 @@
     xmlns:pickers="using:Windows.Storage.Pickers"
     xmlns:Windows10FallCreatorsUpdate="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 5)"
     xmlns:Windows10version1809="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 7)"
+    xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
     mc:Ignorable="d"
     NavigationCacheMode="Required"
     Loaded="Page_Loaded">
@@ -61,7 +62,7 @@
             Grid.ColumnSpan="3"
             DisplayMode="Overlay"
             PaneClosing="MainSplitView_PaneClosing"
-            Background="White" >
+            Background="White">
             <SplitView.Pane>
                 <Pivot x:Name="MainPivot" PivotItemLoaded="MainPivot_PivotItemLoaded">
                     <PivotItem Header="Config" Margin="0">
@@ -101,6 +102,10 @@
                                             </MenuFlyoutItem.Command>
                                         </MenuFlyoutItem>
                                     </MenuFlyout>
+                                    <SolidColorBrush x:Key="ListViewItemForegroundSelected" Color="Black" />
+                                    <SolidColorBrush x:Key="ListViewItemBackgroundSelected" Color="{StaticResource SystemAccentColorLight3}" />
+                                    <SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver" Color="{StaticResource SystemAccentColorLight3}" Opacity=".6" />
+                                    <SolidColorBrush x:Key="ListViewItemBackgroundSelectedPressed" Color="{StaticResource SystemAccentColorLight3}" Opacity=".8" />
                                 </ListView.Resources>
                                 <ListView.ItemTemplate>
                                     <DataTemplate x:DataType="maple_app:ConfigViewModel">
@@ -230,7 +235,7 @@
                     </PivotItem>
                 </Pivot>
             </SplitView.Pane>
-            <Frame x:Name="MainContentFrame" CacheSize="0" />
+            <Frame x:Name="MainContentFrame" CacheSize="2" />
         </SplitView>
 
         <VisualStateManager.VisualStateGroups>

+ 42 - 39
Maple.App/Maple.App.vcxproj

@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.props')" />
+  <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" />
+  <Import Project="..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.props" Condition="Exists('..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.props')" />
   <PropertyGroup Label="Globals">
     <CppWinRTOptimized>true</CppWinRTOptimized>
     <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
@@ -15,7 +16,7 @@
     <ApplicationType>Windows Store</ApplicationType>
     <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
     <WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.22000.0</WindowsTargetPlatformVersion>
-    <WindowsTargetPlatformMinVersion>10.0.15063.0</WindowsTargetPlatformMinVersion>
+    <WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <ItemGroup Label="ProjectConfigurations">
@@ -78,7 +79,6 @@
     <Import Project="PropertySheet.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros">
-    <TargetPlatformMinVersion>10.0.15063.0</TargetPlatformMinVersion>
     <GenerateAppInstallerFile>False</GenerateAppInstallerFile>
     <AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
     <PackageCertificateKeyFile>Maple.App_TemporaryKey.pfx</PackageCertificateKeyFile>
@@ -177,6 +177,10 @@
       <DependentUpon>Model\Netif.idl</DependentUpon>
       <SubType>Code</SubType>
     </ClInclude>
+    <ClInclude Include="MonacoEditPage.h">
+      <DependentUpon>MonacoEditPage.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </ClInclude>
     <ClInclude Include="pch.h" />
     <ClInclude Include="App.h">
       <DependentUpon>App.xaml</DependentUpon>
@@ -204,6 +208,9 @@
     <Page Include="MmdbPage.xaml">
       <SubType>Designer</SubType>
     </Page>
+    <Page Include="MonacoEditPage.xaml">
+      <SubType>Designer</SubType>
+    </Page>
   </ItemGroup>
   <ItemGroup>
     <AppxManifest Include="Package.appxmanifest">
@@ -292,6 +299,10 @@
       <DependentUpon>Model\Netif.idl</DependentUpon>
       <SubType>Code</SubType>
     </ClCompile>
+    <ClCompile Include="MonacoEditPage.cpp">
+      <DependentUpon>MonacoEditPage.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </ClCompile>
     <ClCompile Include="pch.cpp">
       <PrecompiledHeader>Create</PrecompiledHeader>
     </ClCompile>
@@ -335,47 +346,24 @@
     <Midl Include="Model\Netif.idl">
       <SubType>Designer</SubType>
     </Midl>
+    <Midl Include="MonacoEditPage.idl">
+      <DependentUpon>MonacoEditPage.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Midl>
   </ItemGroup>
   <ItemGroup>
     <CopyFileToFolders Include="Config\default.conf">
       <FileType>Document</FileType>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)/Config</DestinationFolders>
+      <DeploymentContent>true</DeploymentContent>
+      <DestinationFolders>$(OutDir)/Config</DestinationFolders>
     </CopyFileToFolders>
     <CopyFileToFolders Include="Config\default.json">
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
       <FileType>Document</FileType>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
-      <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)/Config</DestinationFolders>
-      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)/Config</DestinationFolders>
+      <DeploymentContent>true</DeploymentContent>
+      <DestinationFolders>$(OutDir)/Config</DestinationFolders>
     </CopyFileToFolders>
     <None Include="Maple.App_TemporaryKey.pfx" />
+    <_WildCardCopyFileToFolders Include="MonacoEditor\dist\*" />
     <None Include="packages.config" />
     <None Include="PropertySheet.props" />
   </ItemGroup>
@@ -386,13 +374,28 @@
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
-    <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.targets')" />
+    <Import Project="..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.targets')" />
+    <Import Project="..\packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets" Condition="Exists('..\packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets')" />
+    <Import Project="..\packages\Microsoft.Web.WebView2.1.0.1370.28\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.1370.28\build\native\Microsoft.Web.WebView2.targets')" />
+    <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
   </ImportGroup>
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
     <PropertyGroup>
-      <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
     </PropertyGroup>
-    <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.props'))" />
-    <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.targets'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.props'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.UI.Xaml.2.8.1\build\native\Microsoft.UI.Xaml.targets'))" />
+    <Error Condition="!Exists('..\packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.1370.28\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.1370.28\build\native\Microsoft.Web.WebView2.targets'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
+  </Target>
+  <Target Name="AddWildCardItems" AfterTargets="PrepareForBuild">
+    <ItemGroup>
+      <CopyFileToFolders Include="@(_WildCardCopyFileToFolders)">
+        <DestinationFolders>$(OutDir)\MonacoEditor</DestinationFolders>
+        <DeploymentContent>true</DeploymentContent>
+      </CopyFileToFolders>
+    </ItemGroup>
   </Target>
 </Project>

+ 2 - 1
Maple.App/Maple.App.vcxproj.filters

@@ -168,8 +168,8 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="PropertySheet.props" />
-    <None Include="packages.config" />
     <None Include="Maple.App_TemporaryKey.pfx" />
+    <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
     <Page Include="EditPage.xaml" />
@@ -177,6 +177,7 @@
     <Page Include="MmdbPage.xaml" />
     <Page Include="DatPage.xaml" />
     <Page Include="CertPage.xaml" />
+    <Page Include="MonacoEditPage.xaml" />
   </ItemGroup>
   <ItemGroup>
     <Filter Include="Assets">

+ 130 - 0
Maple.App/MonacoEditPage.cpp

@@ -0,0 +1,130 @@
+#include "pch.h"
+#include "MonacoEditPage.h"
+#if __has_include("MonacoEditPage.g.cpp")
+#include "MonacoEditPage.g.cpp"
+#endif
+
+#include <winrt/Microsoft.Web.WebView2.Core.h>
+#include <nlohmann/json.hpp>
+
+using namespace winrt;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+
+namespace winrt::Maple_App::implementation
+{
+    MonacoEditPage::MonacoEditPage()
+    {
+        InitializeComponent();
+    }
+
+    fire_and_forget MonacoEditPage::Page_Loaded(IInspectable const& sender, RoutedEventArgs const& e)
+    {
+        auto const lifetime{ get_strong() };
+        co_await initializeWebView();
+    }
+    void MonacoEditPage::Page_Unloaded(IInspectable const& sender, RoutedEventArgs const& e)
+    {
+        //
+    }
+    IAsyncAction MonacoEditPage::initializeWebView() {
+        auto const lifetime{ get_strong() };
+        auto const webview = WebView();
+        co_await webview.EnsureCoreWebView2Async();
+        if (std::exchange(m_webviewInitialized, true))
+        {
+            co_return;
+        }
+        auto const packagePath = Windows::ApplicationModel::Package::Current().InstalledPath();
+        auto const configPath = Windows::Storage::ApplicationData::Current().LocalFolder().Path() + L"\\config";
+        webview.CoreWebView2().SetVirtualHostNameToFolderMapping(
+            L"maple-monaco-editor-app-root.com",
+            packagePath,
+            Microsoft::Web::WebView2::Core::CoreWebView2HostResourceAccessKind::DenyCors
+        );
+        webview.CoreWebView2().SetVirtualHostNameToFolderMapping(
+            L"maple-monaco-editor-config-root.com",
+            configPath,
+            Microsoft::Web::WebView2::Core::CoreWebView2HostResourceAccessKind::Allow
+        );
+        webview.Source(Uri{ L"http://maple-monaco-editor-app-root.com/MonacoEditor/editor.html" });
+    }
+
+    fire_and_forget MonacoEditPage::OnNavigatedTo(NavigationEventArgs const& e) {
+        auto const lifetime{ get_strong() };
+        auto const param = e.Parameter().as<Maple_App::ConfigViewModel>();
+        co_await initializeWebView();
+        SaveModifiedContent = [weak = weak_ref{ lifetime }]()->IAsyncAction
+        {
+            if (auto const lifetime{ weak.get() })
+            {
+                lifetime->WebView().ExecuteScriptAsync(hstring{ L"window.mapleHostApi.triggerSave()" });
+            }
+            co_return;
+        };
+
+        if (m_webviewDOMLoaded)
+        {
+            co_await lifetime->WebView().ExecuteScriptAsync(hstring{ L"window.mapleHostApi.loadFile(`http://maple-monaco-editor-config-root.com/" } +
+                param.File().Name() +
+                L"`)");
+        }
+        else {
+            if (!m_webviewDOMLoadedToken) {
+                m_webviewDOMLoadedToken = WebView().CoreWebView2().DOMContentLoaded([=](auto, auto)
+                    {
+                        lifetime->m_webviewDOMLoaded = true;
+                        lifetime->WebView().CoreWebView2().DOMContentLoaded(lifetime->m_webviewDOMLoadedToken);
+                        lifetime->WebView().ExecuteScriptAsync(hstring{ L"window.mapleHostApi.loadFile(`" } +
+                            CONFIG_ROOT_VIRTUAL_HOSTW +
+                            lifetime->m_initialFileName +
+                            L"`)");
+                        lifetime->WebView().WebMessageReceived([](auto const&, auto const& args)
+                            {
+                                auto const json{ args.WebMessageAsJson() };
+                                handleEvent(json);
+                            });
+                    });
+            }
+            m_initialFileName = param.File().Name();
+        }
+    }
+
+    fire_and_forget MonacoEditPage::OnNavigatedFrom(NavigationEventArgs const& e)
+    {
+        // Although editor page will trigger a save before loading new files, there are cases where it does not load a
+        // new file, e.g. user selected a .mmdb file.
+        // TODO: trigger save
+        co_return;
+    }
+
+    IAsyncAction MonacoEditPage::handleEvent(hstring const& eventJson)
+    {
+        nlohmann::json doc;
+        try {
+            doc = nlohmann::json::parse(to_string(eventJson));
+        }
+        catch (...) {}
+
+        if (doc["cmd"] == "save")
+        {
+            try {
+                auto const configDir{ co_await ApplicationData::Current().LocalFolder().CreateFolderAsync(L"config", CreationCollisionOption::OpenIfExists) };
+                auto const configDirPath{ to_string(configDir.Path()) + "\\" };
+                std::string path{ doc["path"] };
+                if (auto const pos{ path.find(CONFIG_ROOT_VIRTUAL_HOST) }; pos != std::string::npos)
+                {
+                    path = path.replace(pos, strlen(CONFIG_ROOT_VIRTUAL_HOST), configDirPath);
+                }
+                auto const file{ co_await StorageFile::GetFileFromPathAsync(to_hstring(path)) };
+                std::string const data{ doc["text"] };
+                co_await FileIO::WriteBytesAsync(file, array_view{
+                    reinterpret_cast<uint8_t const*>(data.data()),
+                    static_cast<uint32_t>(data.size())
+                    });
+            }
+            catch (...) {}
+        }
+        co_return;
+    }
+}

+ 41 - 0
Maple.App/MonacoEditPage.h

@@ -0,0 +1,41 @@
+#pragma once
+
+#include "MonacoEditPage.g.h"
+
+#include <functional>
+
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::Maple_App::implementation
+{
+    constexpr wchar_t const *CONFIG_ROOT_VIRTUAL_HOSTW = L"http://maple-monaco-editor-config-root.com/";
+    constexpr char const *CONFIG_ROOT_VIRTUAL_HOST = "http://maple-monaco-editor-config-root.com/";
+    struct MonacoEditPage : MonacoEditPageT<MonacoEditPage>
+    {
+        MonacoEditPage();
+
+        fire_and_forget OnNavigatedTo(NavigationEventArgs const& e);
+        fire_and_forget OnNavigatedFrom(NavigationEventArgs const& e);
+        fire_and_forget Page_Loaded(IInspectable const& sender, RoutedEventArgs const& e);
+        void Page_Unloaded(IInspectable const& sender, RoutedEventArgs const& e);
+
+        inline static std::function<IAsyncAction()> SaveModifiedContent{ nullptr };
+    private:
+        static IAsyncAction handleEvent(hstring const& eventJson);
+        IAsyncAction initializeWebView();
+
+        bool m_webviewInitialized{};
+        bool m_webviewDOMLoaded{};
+        event_token m_webviewDOMLoadedToken{};
+        hstring m_initialFileName{};
+    };
+}
+
+namespace winrt::Maple_App::factory_implementation
+{
+    struct MonacoEditPage : MonacoEditPageT<MonacoEditPage, implementation::MonacoEditPage>
+    {
+    };
+}

+ 8 - 0
Maple.App/MonacoEditPage.idl

@@ -0,0 +1,8 @@
+namespace Maple_App
+{
+    [default_interface]
+    runtimeclass MonacoEditPage : Windows.UI.Xaml.Controls.Page
+    {
+        MonacoEditPage();
+    }
+}

+ 17 - 0
Maple.App/MonacoEditPage.xaml

@@ -0,0 +1,17 @@
+<Page
+    x:Class="Maple_App.MonacoEditPage"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="using:Maple_App"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
+    mc:Ignorable="d"
+    Loaded="Page_Loaded"
+    Unloaded="Page_Unloaded"
+    NavigationCacheMode="Required">
+
+    <Grid>
+        <muxc:WebView2 x:Name="WebView" />
+    </Grid>
+</Page>

+ 3 - 0
Maple.App/MonacoEditor/.gitignore

@@ -0,0 +1,3 @@
+node_modules
+dist
+.parcel-cache

+ 4389 - 0
Maple.App/MonacoEditor/package-lock.json

@@ -0,0 +1,4389 @@
+{
+  "name": "leaf-conf-editor",
+  "version": "0.1.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "leaf-conf-editor",
+      "version": "0.1.0",
+      "license": "Apache-2.0",
+      "devDependencies": {
+        "monaco-editor": "^0.32.1",
+        "parcel": "^2.7.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/highlight": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.19.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/@babel/highlight/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/source-map": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
+      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@lezer/common": {
+      "version": "0.15.12",
+      "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz",
+      "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==",
+      "dev": true
+    },
+    "node_modules/@lezer/lr": {
+      "version": "0.15.8",
+      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz",
+      "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==",
+      "dev": true,
+      "dependencies": {
+        "@lezer/common": "^0.15.0"
+      }
+    },
+    "node_modules/@lmdb/lmdb-darwin-arm64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz",
+      "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-darwin-x64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz",
+      "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-linux-arm": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz",
+      "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-linux-arm64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz",
+      "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-linux-x64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz",
+      "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-win32-x64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz",
+      "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@mischnic/json-sourcemap": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz",
+      "integrity": "sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==",
+      "dev": true,
+      "dependencies": {
+        "@lezer/common": "^0.15.7",
+        "@lezer/lr": "^0.15.4",
+        "json5": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.1.2.tgz",
+      "integrity": "sha512-TyVLn3S/+ikMDsh0gbKv2YydKClN8HaJDDpONlaZR+LVJmsxLFUgA+O7zu59h9+f9gX1aj/ahw9wqa6rosmrYQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.1.2.tgz",
+      "integrity": "sha512-YPXtcVkhmVNoMGlqp81ZHW4dMxK09msWgnxtsDpSiZwTzUBG2N+No2bsr7WMtBKCVJMSD6mbAl7YhKUqkp/Few==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.1.2.tgz",
+      "integrity": "sha512-42R4MAFeIeNn+L98qwxAt360bwzX2Kf0ZQkBBucJ2Ircza3asoY4CDbgiu9VWklq8gWJVSJSJBwDI+c/THiWkA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.1.2.tgz",
+      "integrity": "sha512-vHZ2JiOWF2+DN9lzltGbhtQNzDo8fKFGrf37UJrgqxU0yvtERrzUugnfnX1wmVfFhSsF8OxrfqiNOUc5hko1Zg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.1.2.tgz",
+      "integrity": "sha512-RjRoRxg7Q3kPAdUSC5EUUPlwfMkIVhmaRTIe+cqHbKrGZ4M6TyCA/b5qMaukQ/1CHWrqYY2FbKOAU8Hg0pQFzg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.1.2.tgz",
+      "integrity": "sha512-rIZVR48zA8hGkHIK7ED6+ZiXsjRCcAVBJbm8o89OKAMTmEAQ2QvoOxoiu3w2isAaWwzgtQIOFIqHwvZDyLKCvw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@parcel/bundler-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.7.0.tgz",
+      "integrity": "sha512-PU5MtWWhc+dYI9x8mguYnm9yiG6TkI7niRpxgJgtqAyGHuEyNXVBQQ0X+qyOF4D9LdankBf8uNN18g31IET2Zg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/cache": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.7.0.tgz",
+      "integrity": "sha512-JlXNoZXcWzLKdDlfeF3dIj5Vtel5T9vtdBN72PJ+cjC4qNHk4Uwvc5sfOBELuibGN0bVu2bwY9nUgSwCiB1iIA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/fs": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "lmdb": "2.5.2"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@parcel/codeframe": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.7.0.tgz",
+      "integrity": "sha512-UTKx0jejJmmO1dwTHSJuRgrO8N6PMlkxRT6sew8N6NC3Bgv6pu0EbO+RtlWt/jCvzcdLOPdIoTzj4MMZvgcMYg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/compressor-raw": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.7.0.tgz",
+      "integrity": "sha512-SCXwnOOQT6EmpusBsYWNQ/RFri+2JnKuE0gMSf2dROl2xbererX45FYzeDplWALCKAdjMNDpFwU+FyMYoVZSCQ==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/config-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.7.0.tgz",
+      "integrity": "sha512-ZzsLr97AYrz8c9k6qn3DlqPzifi3vbP7q3ynUrAFxmt0L4+K0H9N508ZkORYmCgaFjLIQ8Y3eWpwCJ0AewPNIg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/bundler-default": "2.7.0",
+        "@parcel/compressor-raw": "2.7.0",
+        "@parcel/namer-default": "2.7.0",
+        "@parcel/optimizer-css": "2.7.0",
+        "@parcel/optimizer-htmlnano": "2.7.0",
+        "@parcel/optimizer-image": "2.7.0",
+        "@parcel/optimizer-svgo": "2.7.0",
+        "@parcel/optimizer-terser": "2.7.0",
+        "@parcel/packager-css": "2.7.0",
+        "@parcel/packager-html": "2.7.0",
+        "@parcel/packager-js": "2.7.0",
+        "@parcel/packager-raw": "2.7.0",
+        "@parcel/packager-svg": "2.7.0",
+        "@parcel/reporter-dev-server": "2.7.0",
+        "@parcel/resolver-default": "2.7.0",
+        "@parcel/runtime-browser-hmr": "2.7.0",
+        "@parcel/runtime-js": "2.7.0",
+        "@parcel/runtime-react-refresh": "2.7.0",
+        "@parcel/runtime-service-worker": "2.7.0",
+        "@parcel/transformer-babel": "2.7.0",
+        "@parcel/transformer-css": "2.7.0",
+        "@parcel/transformer-html": "2.7.0",
+        "@parcel/transformer-image": "2.7.0",
+        "@parcel/transformer-js": "2.7.0",
+        "@parcel/transformer-json": "2.7.0",
+        "@parcel/transformer-postcss": "2.7.0",
+        "@parcel/transformer-posthtml": "2.7.0",
+        "@parcel/transformer-raw": "2.7.0",
+        "@parcel/transformer-react-refresh-wrap": "2.7.0",
+        "@parcel/transformer-svg": "2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@parcel/core": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.7.0.tgz",
+      "integrity": "sha512-7yKZUdh314Q/kU/9+27ZYTfcnXS6VYHuG+iiUlIohnvUUybxLqVJhdMU9Q+z2QcPka1IdJWz4K4Xx0y6/4goyg==",
+      "dev": true,
+      "dependencies": {
+        "@mischnic/json-sourcemap": "^0.1.0",
+        "@parcel/cache": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/events": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/graph": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/package-manager": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "abortcontroller-polyfill": "^1.1.9",
+        "base-x": "^3.0.8",
+        "browserslist": "^4.6.6",
+        "clone": "^2.1.1",
+        "dotenv": "^7.0.0",
+        "dotenv-expand": "^5.1.0",
+        "json5": "^2.2.0",
+        "msgpackr": "^1.5.4",
+        "nullthrows": "^1.1.1",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/css": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmjs.org/@parcel/css/-/css-1.14.0.tgz",
+      "integrity": "sha512-r5tJWe6NF6lesfPw1N3g7N7WUKpHqi2ONnw9wl5ccSGGIxkmgcPaPQxfvmhdjXvQnktSuIOR0HjQXVXu+/en/w==",
+      "dev": true,
+      "dependencies": {
+        "lightningcss": "^1.14.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/diagnostic": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.7.0.tgz",
+      "integrity": "sha512-pdq/cTwVoL0n8yuDCRXFRSQHVWdmmIXPt3R3iT4KtYDYvOrMT2dLPT79IMqQkhYPANW8GuL15n/WxRngfRdkug==",
+      "dev": true,
+      "dependencies": {
+        "@mischnic/json-sourcemap": "^0.1.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/events": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.7.0.tgz",
+      "integrity": "sha512-kQDwMKgZ1U4M/G17qeDYF6bW5kybluN6ajYPc7mZcrWg+trEI/oXi81GMFaMX0BSUhwhbiN5+/Vb2wiG/Sn6ig==",
+      "dev": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/fs": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.7.0.tgz",
+      "integrity": "sha512-PU5fo4Hh8y03LZgemgVREttc0wyHQUNmsJCybxTB7EjJie2CqJRumo+DFppArlvdchLwJdc9em03yQV/GNWrEg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/fs-search": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/watcher": "^2.0.0",
+        "@parcel/workers": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@parcel/fs-search": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.7.0.tgz",
+      "integrity": "sha512-K1Hv25bnRpwQVA15RvcRuB8ZhfclnCHA8N8L6w7Ul1ncSJDxCIkIAc5hAubYNNYW3kWjCC2SOaEgFKnbvMllEQ==",
+      "dev": true,
+      "dependencies": {
+        "detect-libc": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/graph": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.7.0.tgz",
+      "integrity": "sha512-Q6E94GS6q45PtsZh+m+gvFRp/N1Qopxhu2sxjcWsGs5iBd6IWn2oYLWOH5iVzEjWuYpW2HkB08lH6J50O63uOA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/hash": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.7.0.tgz",
+      "integrity": "sha512-k6bSKnIlPJMPU3yjQzfgfvF9zuJZGOAlJgzpL4BbWvdbE8BTdjzLcFn0Ujrtud94EgIkiXd22sC2HpCUWoHGdA==",
+      "dev": true,
+      "dependencies": {
+        "detect-libc": "^1.0.3",
+        "xxhash-wasm": "^0.4.2"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/logger": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.7.0.tgz",
+      "integrity": "sha512-qjMY/bYo38+o+OiIrTRldU9CwL1E7J72t+xkTP8QIcUxLWz5LYR0YbynZUVulmBSfqsykjjxCy4a+8siVr+lPw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/events": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/markdown-ansi": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.7.0.tgz",
+      "integrity": "sha512-ipOX0D6FVZFEXeb/z8MnTMq2RQEIuaILY90olVIuHEFLHHfOPEn+RK3u13HA1ChF5/9E3cMD79tu6x9JL9Kqag==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/namer-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.7.0.tgz",
+      "integrity": "sha512-lIKMdsmi//7fepecNDYmJYzBlL91HifPsX03lJCdu1dC6q5fBs+gG0XjKKG7yPnSCw1qH/4m7drzt9+dRZYAHQ==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/node-resolver-core": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.7.0.tgz",
+      "integrity": "sha512-5UJQHalqMxdhJIs2hhqQzFfQpF7+NAowsRq064lYtiRvcD8wMr3OOQ9wd1iazGpFSl4JKdT7BwDU9/miDJmanQ==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/optimizer-css": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.7.0.tgz",
+      "integrity": "sha512-IfnOMACqhcAclKyOW9X9JpsknB6OShk9OVvb8EvbDTKHJhQHNNmzE88OkSI/pS3ZVZP9Zj+nWcVHguV+kvDeiQ==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/css": "^1.12.2",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "browserslist": "^4.6.6",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/optimizer-htmlnano": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.7.0.tgz",
+      "integrity": "sha512-5QrGdWS5Hi4VXE3nQNrGqugmSXt68YIsWwKRAdarOxzyULSJS3gbCiQOXqIPRJobfZjnSIcdtkyxSiCUe1inIA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "htmlnano": "^2.0.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "svgo": "^2.4.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/optimizer-image": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.7.0.tgz",
+      "integrity": "sha512-EnaXz5UjR67FUu0BEcqZTT9LsbB/iFAkkghCotbnbOuC5QQsloq6tw54TKU3y+R3qsjgUoMtGxPcGfVoXxZXYw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "detect-libc": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/optimizer-svgo": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.7.0.tgz",
+      "integrity": "sha512-IO1JV4NpfP3V7FrhsqCcV8pDQIHraFi1/ZvEJyssITxjH49Im/txKlwMiQuZZryAPn8Xb8g395Muawuk6AK6sg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "svgo": "^2.4.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/optimizer-terser": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.7.0.tgz",
+      "integrity": "sha512-07VZjIO8xsl2/WmS/qHI8lI/cpu47iS9eRpqwfZEEsdk1cfz50jhWkmFudHBxiHGMfcZ//1+DdaPg9RDBWZtZA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "terser": "^5.2.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/package-manager": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.7.0.tgz",
+      "integrity": "sha512-wmfSX1mRrTi8MeA4KrnPk/x7zGUsILCQmTo6lA4gygzAxDbM1pGuyFN8/Kt0y0SFO2lbljARtD/4an5qdotH+Q==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@parcel/packager-css": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.7.0.tgz",
+      "integrity": "sha512-44nzZwu+ssGuiFmYM6cf/Y4iChiUZ4DUzzpegnGlhXtKJKe4NHntxThJynuRZWKN2AAf48avApDpimg2jW0KDw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/packager-html": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.7.0.tgz",
+      "integrity": "sha512-Zgqd7sdcY/UnR370GR0q2ilmEohUDXsO8A1F28QCJzIsR1iCB6KRUT74+pawfQ1IhXZLaaFLLYe0UWcfm0JeXg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/packager-js": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.7.0.tgz",
+      "integrity": "sha512-wTRdM81PgRVDzWGXdWmqLwguWnTYWzhEDdjXpW2n8uMOu/CjHhMtogk65aaYk3GOnq6OBL/NsrmBiV/zKPj1vA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "globals": "^13.2.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/packager-raw": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.7.0.tgz",
+      "integrity": "sha512-jg2Zp8dI5VpIQlaeahXDCfrPN9m/DKht1NkR9P2CylMAwqCcc1Xc1RRiF0wfwcPZpPMpq1265n+4qnB7rjGBlA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/packager-svg": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.7.0.tgz",
+      "integrity": "sha512-EmJg3HpD6/xxKBjir/CdCKJZwI24iVfBuxRS9LUp3xHAIebOzVh1z6IN+i2Di5+NyRwfOFaLliL4uMa1zwbyCA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "posthtml": "^0.16.4"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/plugin": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.7.0.tgz",
+      "integrity": "sha512-qqgx+nnMn6/0lRc4lKbLGmhNtBiT93S2gFNB4Eb4Pfz/SxVYoW+fmml+KdfOSiZffWOAH5L6NwhyD7N8aSikzw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/types": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/reporter-cli": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.7.0.tgz",
+      "integrity": "sha512-80gEODg8cnAmnxGVuaSVDo8JJ54P9AA2bHwSs1cIkHWlJ3BjDQb83H31bBHncJ5Kn5kQ/j+7WjlqHpTCiOR9PA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "chalk": "^4.1.0",
+        "term-size": "^2.2.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/reporter-dev-server": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.7.0.tgz",
+      "integrity": "sha512-ySuou5addK8fGue8aXzo536BaEjMujDrEc1xkp4TasInXHVcA98b+SYX5NAZTGob5CxKvZQ5ylhg77zW30B+iA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/resolver-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.7.0.tgz",
+      "integrity": "sha512-v8TvWsbLK7/q7n4gv6OrYNbW18xUx4zKbVMGZb1u4yMhzEH4HFr1D9OeoTq3jk+ximAigds8B6triQbL5exF7A==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/node-resolver-core": "2.7.0",
+        "@parcel/plugin": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/runtime-browser-hmr": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.7.0.tgz",
+      "integrity": "sha512-PLbMLdclQeYsi2LkilZVGFV1n3y55G1jaBvby4ekedUZjMw3SWdMY2tDxgSDdFWfLCnYHJXdGUQSzGGi1kPzjA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/runtime-js": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.7.0.tgz",
+      "integrity": "sha512-9/YUZTBNrSN2H6rbz/o1EOM0O7I3ZR/x9IDzxjJBD6Mi+0uCgCD02aedare/SNr1qgnbZZWmhpOzC+YgREcfLA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/runtime-react-refresh": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.7.0.tgz",
+      "integrity": "sha512-vDKO0rWqRzEpmvoZ4kkYUiSsTxT5NnH904BFPFxKI0wJCl6yEmPuEifmATo73OuYhP6jIP3Qfl1R4TtiDFPJ1Q==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "react-error-overlay": "6.0.9",
+        "react-refresh": "^0.9.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/runtime-service-worker": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.7.0.tgz",
+      "integrity": "sha512-uD2pAV0yV6+e7JaWH4KVPbG+zRCrxr/OACyS9tIh+Q/R1vRmh8zGM3yhdrcoiZ7tFOnM72vd6xY11eTrUsSVig==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/source-map": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz",
+      "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==",
+      "dev": true,
+      "dependencies": {
+        "detect-libc": "^1.0.3"
+      },
+      "engines": {
+        "node": "^12.18.3 || >=14"
+      }
+    },
+    "node_modules/@parcel/transformer-babel": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.7.0.tgz",
+      "integrity": "sha512-7iklDXXnKH1530+QbI+e4kIJ+Q1puA1ulRS10db3aUJMj5GnvXGDFwhSZ7+T1ps66QHO7cVO29VlbqiRDarH1Q==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "browserslist": "^4.6.6",
+        "json5": "^2.2.0",
+        "nullthrows": "^1.1.1",
+        "semver": "^5.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-css": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.7.0.tgz",
+      "integrity": "sha512-J4EpWK9spQpXyNCmKK8Xnane0xW/1B/EAmfp7Fiv7g+5yUjY4ODf4KUugvE+Eb2gekPkhOKNHermO2KrX0/PFA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/css": "^1.12.2",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "browserslist": "^4.6.6",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-html": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.7.0.tgz",
+      "integrity": "sha512-wYJl5rn81W+Rlk9oQwDJcjoVsWVDKyeri84FzmlGXOsg0EYgnqOiG+3MDM8GeZjfuGe5fuoum4eqZeS0WdUHXw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "posthtml-parser": "^0.10.1",
+        "posthtml-render": "^3.0.0",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-image": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.7.0.tgz",
+      "integrity": "sha512-mhi9/R5/ULhCkL2COVIKhNFoLDiZwQgprdaTJr5fnODggVxEX5o7ebFV6KNLMTEkwZUJWoB1hL0ziI0++DtoFA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@parcel/transformer-js": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.7.0.tgz",
+      "integrity": "sha512-mzerR+D4rDomUSIk5RSTa2w+DXBdXUeQrpDO74WCDdpDi1lIl8ppFpqtmU7O6y6p8QsgkmS9b0g/vhcry6CJTA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "@swc/helpers": "^0.4.2",
+        "browserslist": "^4.6.6",
+        "detect-libc": "^1.0.3",
+        "nullthrows": "^1.1.1",
+        "regenerator-runtime": "^0.13.7",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@parcel/transformer-json": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.7.0.tgz",
+      "integrity": "sha512-RQjuxBpYOch+kr4a0zi77KJtOLTPYRM7iq4NN80zKnA0r0dwDUCxZBtaj2l0O0o3R4MMJnm+ncP+cB7XR7dZYA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "json5": "^2.2.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-postcss": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.7.0.tgz",
+      "integrity": "sha512-b6RskXBWf0MjpC9qjR2dQ1ZdRnlOiKYseG5CEovWCqM218RtdydFKz7jS+5Gxkb6qBtOG7zGPONXdPe+gTILcA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "clone": "^2.1.1",
+        "nullthrows": "^1.1.1",
+        "postcss-value-parser": "^4.2.0",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-posthtml": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.7.0.tgz",
+      "integrity": "sha512-cP8YOiSynWJ1ycmBlhnnHeuQb2cwmklZ+BNyLUktj5p78kDy2de7VjX+dRNRHoW4H9OgEcSF4UEfDVVz5RYIhw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "posthtml-parser": "^0.10.1",
+        "posthtml-render": "^3.0.0",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-raw": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.7.0.tgz",
+      "integrity": "sha512-sDnItWCFSDez0izK1i5cgv+kXzZTbcJh4rNpVIgmE1kBLvAz608sqgcCkavb2wVJIvLesxYM+5G4p1CwkDlZ1g==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-react-refresh-wrap": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.7.0.tgz",
+      "integrity": "sha512-1vRmIJzyBA1nIiXTAU6tZExq2FvJj/2F0ft6KDw8GYPv0KjmdiPo/PmaZ7JeSVOM6SdXQIQCbTmp1vkMP7DtkA==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "react-refresh": "^0.9.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/transformer-svg": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.7.0.tgz",
+      "integrity": "sha512-ioER37zceuuE+K6ZrnjCyMUWEnv+63hIAFResc1OXxRhyt+7kzMz9ZqK0Mt6QMLwl1dxhkLmrU41n9IxzKZuSQ==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "posthtml-parser": "^0.10.1",
+        "posthtml-render": "^3.0.0",
+        "semver": "^5.7.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0",
+        "parcel": "^2.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/types": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.7.0.tgz",
+      "integrity": "sha512-+dhXVUnseTCpJvBTGMp0V6X13z6O/A/+CUtwEpMGZ8XSmZ4Gk44GvaTiBOp0bJpWG4fvCKp+UmC8PYbrDiiziw==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/cache": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/package-manager": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/workers": "2.7.0",
+        "utility-types": "^3.10.0"
+      }
+    },
+    "node_modules/@parcel/utils": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.7.0.tgz",
+      "integrity": "sha512-jNZ5bIGg1r1RDRKi562o4kuVwnz+XJ2Ie3b0Zwrqwvgfj6AbRFIKzDd+h85dWWmcDYzKUbHp11u6VJl1u8Vapg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/codeframe": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/markdown-ansi": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "chalk": "^4.1.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.5.tgz",
+      "integrity": "sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "node-addon-api": "^3.2.1",
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/workers": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.7.0.tgz",
+      "integrity": "sha512-99VfaOX+89+RaoTSyH9ZQtkMBFZBFMvJmVJ/GeJT6QCd2wtKBStTHlaSnQOkLD/iRjJCNwV2xpZmm8YkTwV+hg==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "chrome-trace-event": "^1.0.2",
+        "nullthrows": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "peerDependencies": {
+        "@parcel/core": "^2.7.0"
+      }
+    },
+    "node_modules/@swc/helpers": {
+      "version": "0.4.12",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.12.tgz",
+      "integrity": "sha512-R6RmwS9Dld5lNvwKlPn62+piU+WDG1sMfsnfJioXCciyko/gZ0DQ4Mqglhq1iGU1nQ/RcGkAwfMH+elMSkJH3Q==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@trysound/sax": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
+      "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "dev": true
+    },
+    "node_modules/abortcontroller-polyfill": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz",
+      "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==",
+      "dev": true
+    },
+    "node_modules/acorn": {
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+      "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/base-x": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
+      "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.4",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
+      "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001400",
+        "electron-to-chromium": "^1.4.251",
+        "node-releases": "^2.0.6",
+        "update-browserslist-db": "^1.0.9"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001423",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz",
+      "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        }
+      ]
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/chrome-trace-event": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
+    "node_modules/clone": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+      "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/cosmiconfig": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
+      "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/css-select": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+      "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.0.1",
+        "domhandler": "^4.3.1",
+        "domutils": "^2.8.0",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-tree": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+      "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+      "dev": true,
+      "dependencies": {
+        "mdn-data": "2.0.14",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/csso": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
+      "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
+      "dev": true,
+      "dependencies": {
+        "css-tree": "^1.1.2"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+      "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+      "dev": true,
+      "bin": {
+        "detect-libc": "bin/detect-libc.js"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+      "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.0.1",
+        "domhandler": "^4.2.0",
+        "entities": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/dom-serializer/node_modules/entities": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+      "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
+    },
+    "node_modules/domhandler": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+      "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.2.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+      "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+      "dev": true,
+      "dependencies": {
+        "dom-serializer": "^1.0.1",
+        "domelementtype": "^2.2.0",
+        "domhandler": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/dotenv": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz",
+      "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/dotenv-expand": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
+      "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
+      "dev": true
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.284",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
+      "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
+      "dev": true
+    },
+    "node_modules/entities": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+      "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/get-port": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz",
+      "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/globals": {
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/htmlnano": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.2.tgz",
+      "integrity": "sha512-+ZrQFS4Ub+zd+/fWwfvoYCEGNEa0/zrpys6CyXxvZDwtL7Pl+pOtRkiujyvBQ7Lmfp7/iEPxtOFgxWA16Gkj3w==",
+      "dev": true,
+      "dependencies": {
+        "cosmiconfig": "^7.0.1",
+        "posthtml": "^0.16.5",
+        "timsort": "^0.3.0"
+      },
+      "peerDependencies": {
+        "cssnano": "^5.0.11",
+        "postcss": "^8.3.11",
+        "purgecss": "^4.0.3",
+        "relateurl": "^0.2.7",
+        "srcset": "^5.0.0",
+        "svgo": "^2.8.0",
+        "terser": "^5.10.0",
+        "uncss": "^0.17.3"
+      },
+      "peerDependenciesMeta": {
+        "cssnano": {
+          "optional": true
+        },
+        "postcss": {
+          "optional": true
+        },
+        "purgecss": {
+          "optional": true
+        },
+        "relateurl": {
+          "optional": true
+        },
+        "srcset": {
+          "optional": true
+        },
+        "svgo": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "uncss": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
+      "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
+      "dev": true,
+      "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "dependencies": {
+        "domelementtype": "^2.0.1",
+        "domhandler": "^4.2.2",
+        "domutils": "^2.8.0",
+        "entities": "^3.0.1"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "node_modules/is-json": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
+      "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
+      "dev": true
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "node_modules/json5": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
+      "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+      "dev": true,
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/lightningcss": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.16.0.tgz",
+      "integrity": "sha512-5+ZS9h+xeADcJTF2oRCT3yNZBlDYyOgQSdrWNBCqsIwm8ucKbF061OBVv/WHP4Zk8FToNhwFklk/hMuOngqsIg==",
+      "dev": true,
+      "dependencies": {
+        "detect-libc": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "lightningcss-darwin-arm64": "1.16.0",
+        "lightningcss-darwin-x64": "1.16.0",
+        "lightningcss-linux-arm-gnueabihf": "1.16.0",
+        "lightningcss-linux-arm64-gnu": "1.16.0",
+        "lightningcss-linux-arm64-musl": "1.16.0",
+        "lightningcss-linux-x64-gnu": "1.16.0",
+        "lightningcss-linux-x64-musl": "1.16.0",
+        "lightningcss-win32-x64-msvc": "1.16.0"
+      }
+    },
+    "node_modules/lightningcss-darwin-arm64": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.16.0.tgz",
+      "integrity": "sha512-gIhz6eZFwsC4oVMjBGQ3QWDdLQY7vcXFyM/x91PilgHqu63B9uBa10EZA75YoTEkbKhoz0uDCqyHh/EoF1GrkQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-x64": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.16.0.tgz",
+      "integrity": "sha512-kLPi+OEpDj3UGY6DC8TfjbcULJDKMP+TVKSlrEkNGn8t1YRzi2g4oy7UVTSB5AnSbT0CusUItzdVjHQ49EdoNA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm-gnueabihf": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.16.0.tgz",
+      "integrity": "sha512-oSwEbvXUPr//H/ainBRJXTxHerlheee/KgkTTmAQWiVnt8HV+bRohTBWWPBy5ZArgiGLwj7ogv45istgljPN2Q==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-gnu": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.16.0.tgz",
+      "integrity": "sha512-Drq9BSVIvmV9zsDJbCZWCulMvKMQWFIlYXPCKV/iwRj+ZAJ1BRngma0cNHB6uW7Wac8Jg04CJN5IA4ELE3J+cQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-musl": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.16.0.tgz",
+      "integrity": "sha512-1QXWStnTEo4RFQf0mfGhRyNUeEHilCZ0NA97XgwKwrYr/M7sYKU/1HWY00dPxFJ6GITR2pfJGo9xi3ScSSBxbA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-gnu": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.16.0.tgz",
+      "integrity": "sha512-gD2eQYD5OFs1p83R0TcMCEc5HRyJES4lR4THmclv7khm3dc9vc+2VT0kFBPxO1L2AwlZuvXaaMan7X1Ul7uSfA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-musl": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.16.0.tgz",
+      "integrity": "sha512-HJsKeYxloEvg2WCQhtYPqzZUliLu9JBJNeI5y9cPQeDR/7ayGGLbVhJaotPtzJkElOFL/SaXsS+FRuH4w+yafg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-x64-msvc": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.16.0.tgz",
+      "integrity": "sha512-h4ayyAlOMLUHV9NdofcIu79aEjmly93adVxcg5wDJpkvMiwDTufEN30M8G4gGcjo1JE5jFjAcyQcRpXYkYcemA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "node_modules/lmdb": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz",
+      "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "msgpackr": "^1.5.4",
+        "node-addon-api": "^4.3.0",
+        "node-gyp-build-optional-packages": "5.0.3",
+        "ordered-binary": "^1.2.4",
+        "weak-lru-cache": "^1.2.2"
+      },
+      "optionalDependencies": {
+        "@lmdb/lmdb-darwin-arm64": "2.5.2",
+        "@lmdb/lmdb-darwin-x64": "2.5.2",
+        "@lmdb/lmdb-linux-arm": "2.5.2",
+        "@lmdb/lmdb-linux-arm64": "2.5.2",
+        "@lmdb/lmdb-linux-x64": "2.5.2",
+        "@lmdb/lmdb-win32-x64": "2.5.2"
+      }
+    },
+    "node_modules/lmdb/node_modules/node-addon-api": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+      "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+      "dev": true
+    },
+    "node_modules/mdn-data": {
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+      "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+      "dev": true
+    },
+    "node_modules/monaco-editor": {
+      "version": "0.32.1",
+      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.32.1.tgz",
+      "integrity": "sha512-LUt2wsUvQmEi2tfTOK+tjAPvt7eQ+K5C4rZPr6SeuyzjAuAHrIvlUloTcOiGjZW3fn3a/jFQCONrEJbNOaCqbA==",
+      "dev": true
+    },
+    "node_modules/msgpackr": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.7.2.tgz",
+      "integrity": "sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==",
+      "dev": true,
+      "optionalDependencies": {
+        "msgpackr-extract": "^2.1.2"
+      }
+    },
+    "node_modules/msgpackr-extract": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.1.2.tgz",
+      "integrity": "sha512-cmrmERQFb19NX2JABOGtrKdHMyI6RUyceaPBQ2iRz9GnDkjBWFjNJC0jyyoOfZl2U/LZE3tQCCQc4dlRyA8mcA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "dependencies": {
+        "node-gyp-build-optional-packages": "5.0.3"
+      },
+      "bin": {
+        "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+      },
+      "optionalDependencies": {
+        "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-linux-arm": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-linux-x64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-win32-x64": "2.1.2"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+      "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
+      "dev": true
+    },
+    "node_modules/node-gyp-build": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz",
+      "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==",
+      "dev": true,
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
+    "node_modules/node-gyp-build-optional-packages": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz",
+      "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==",
+      "dev": true,
+      "bin": {
+        "node-gyp-build-optional-packages": "bin.js",
+        "node-gyp-build-optional-packages-optional": "optional.js",
+        "node-gyp-build-optional-packages-test": "build-test.js"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
+      "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
+      "dev": true
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/nullthrows": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
+      "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==",
+      "dev": true
+    },
+    "node_modules/ordered-binary": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.4.0.tgz",
+      "integrity": "sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==",
+      "dev": true
+    },
+    "node_modules/parcel": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.7.0.tgz",
+      "integrity": "sha512-pRYwnivwtNP0tip8xYSo4zCB0XhLt7/gJzP1p8OovCqkmFjG9VG+GW9TcAKqMIo0ovEa9tT+/s6gY1Qy+BONGQ==",
+      "dev": true,
+      "dependencies": {
+        "@parcel/config-default": "2.7.0",
+        "@parcel/core": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/events": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/package-manager": "2.7.0",
+        "@parcel/reporter-cli": "2.7.0",
+        "@parcel/reporter-dev-server": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "chalk": "^4.1.0",
+        "commander": "^7.0.0",
+        "get-port": "^4.2.0",
+        "v8-compile-cache": "^2.0.0"
+      },
+      "bin": {
+        "parcel": "lib/bin.js"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "dev": true
+    },
+    "node_modules/posthtml": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
+      "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
+      "dev": true,
+      "dependencies": {
+        "posthtml-parser": "^0.11.0",
+        "posthtml-render": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/posthtml-parser": {
+      "version": "0.10.2",
+      "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz",
+      "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==",
+      "dev": true,
+      "dependencies": {
+        "htmlparser2": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/posthtml-render": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
+      "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
+      "dev": true,
+      "dependencies": {
+        "is-json": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/posthtml/node_modules/posthtml-parser": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
+      "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
+      "dev": true,
+      "dependencies": {
+        "htmlparser2": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/react-error-overlay": {
+      "version": "6.0.9",
+      "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
+      "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==",
+      "dev": true
+    },
+    "node_modules/react-refresh": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz",
+      "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.13.10",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz",
+      "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==",
+      "dev": true
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/stable": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
+      "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+      "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
+      "dev": true
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/svgo": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
+      "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
+      "dev": true,
+      "dependencies": {
+        "@trysound/sax": "0.2.0",
+        "commander": "^7.2.0",
+        "css-select": "^4.1.3",
+        "css-tree": "^1.1.3",
+        "csso": "^4.2.0",
+        "picocolors": "^1.0.0",
+        "stable": "^0.1.8"
+      },
+      "bin": {
+        "svgo": "bin/svgo"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/term-size": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
+      "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/terser": {
+      "version": "5.15.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz",
+      "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/source-map": "^0.3.2",
+        "acorn": "^8.5.0",
+        "commander": "^2.20.0",
+        "source-map-support": "~0.5.20"
+      },
+      "bin": {
+        "terser": "bin/terser"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/terser/node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "node_modules/timsort": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
+      "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
+      "dev": true
+    },
+    "node_modules/tslib": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+      "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+      "dev": true
+    },
+    "node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "browserslist-lint": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/utility-types": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
+      "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "node_modules/weak-lru-cache": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz",
+      "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==",
+      "dev": true
+    },
+    "node_modules/xxhash-wasm": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz",
+      "integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==",
+      "dev": true
+    },
+    "node_modules/yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    }
+  },
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.18.6"
+      }
+    },
+    "@babel/helper-validator-identifier": {
+      "version": "7.19.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+      "dev": true
+    },
+    "@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true
+    },
+    "@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "dev": true
+    },
+    "@jridgewell/source-map": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
+      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "@lezer/common": {
+      "version": "0.15.12",
+      "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz",
+      "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==",
+      "dev": true
+    },
+    "@lezer/lr": {
+      "version": "0.15.8",
+      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz",
+      "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==",
+      "dev": true,
+      "requires": {
+        "@lezer/common": "^0.15.0"
+      }
+    },
+    "@lmdb/lmdb-darwin-arm64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz",
+      "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==",
+      "dev": true,
+      "optional": true
+    },
+    "@lmdb/lmdb-darwin-x64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz",
+      "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==",
+      "dev": true,
+      "optional": true
+    },
+    "@lmdb/lmdb-linux-arm": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz",
+      "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==",
+      "dev": true,
+      "optional": true
+    },
+    "@lmdb/lmdb-linux-arm64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz",
+      "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==",
+      "dev": true,
+      "optional": true
+    },
+    "@lmdb/lmdb-linux-x64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz",
+      "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==",
+      "dev": true,
+      "optional": true
+    },
+    "@lmdb/lmdb-win32-x64": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz",
+      "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==",
+      "dev": true,
+      "optional": true
+    },
+    "@mischnic/json-sourcemap": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz",
+      "integrity": "sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==",
+      "dev": true,
+      "requires": {
+        "@lezer/common": "^0.15.7",
+        "@lezer/lr": "^0.15.4",
+        "json5": "^2.2.1"
+      }
+    },
+    "@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.1.2.tgz",
+      "integrity": "sha512-TyVLn3S/+ikMDsh0gbKv2YydKClN8HaJDDpONlaZR+LVJmsxLFUgA+O7zu59h9+f9gX1aj/ahw9wqa6rosmrYQ==",
+      "dev": true,
+      "optional": true
+    },
+    "@msgpackr-extract/msgpackr-extract-darwin-x64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.1.2.tgz",
+      "integrity": "sha512-YPXtcVkhmVNoMGlqp81ZHW4dMxK09msWgnxtsDpSiZwTzUBG2N+No2bsr7WMtBKCVJMSD6mbAl7YhKUqkp/Few==",
+      "dev": true,
+      "optional": true
+    },
+    "@msgpackr-extract/msgpackr-extract-linux-arm": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.1.2.tgz",
+      "integrity": "sha512-42R4MAFeIeNn+L98qwxAt360bwzX2Kf0ZQkBBucJ2Ircza3asoY4CDbgiu9VWklq8gWJVSJSJBwDI+c/THiWkA==",
+      "dev": true,
+      "optional": true
+    },
+    "@msgpackr-extract/msgpackr-extract-linux-arm64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.1.2.tgz",
+      "integrity": "sha512-vHZ2JiOWF2+DN9lzltGbhtQNzDo8fKFGrf37UJrgqxU0yvtERrzUugnfnX1wmVfFhSsF8OxrfqiNOUc5hko1Zg==",
+      "dev": true,
+      "optional": true
+    },
+    "@msgpackr-extract/msgpackr-extract-linux-x64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.1.2.tgz",
+      "integrity": "sha512-RjRoRxg7Q3kPAdUSC5EUUPlwfMkIVhmaRTIe+cqHbKrGZ4M6TyCA/b5qMaukQ/1CHWrqYY2FbKOAU8Hg0pQFzg==",
+      "dev": true,
+      "optional": true
+    },
+    "@msgpackr-extract/msgpackr-extract-win32-x64": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.1.2.tgz",
+      "integrity": "sha512-rIZVR48zA8hGkHIK7ED6+ZiXsjRCcAVBJbm8o89OKAMTmEAQ2QvoOxoiu3w2isAaWwzgtQIOFIqHwvZDyLKCvw==",
+      "dev": true,
+      "optional": true
+    },
+    "@parcel/bundler-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.7.0.tgz",
+      "integrity": "sha512-PU5MtWWhc+dYI9x8mguYnm9yiG6TkI7niRpxgJgtqAyGHuEyNXVBQQ0X+qyOF4D9LdankBf8uNN18g31IET2Zg==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/cache": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.7.0.tgz",
+      "integrity": "sha512-JlXNoZXcWzLKdDlfeF3dIj5Vtel5T9vtdBN72PJ+cjC4qNHk4Uwvc5sfOBELuibGN0bVu2bwY9nUgSwCiB1iIA==",
+      "dev": true,
+      "requires": {
+        "@parcel/fs": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "lmdb": "2.5.2"
+      }
+    },
+    "@parcel/codeframe": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.7.0.tgz",
+      "integrity": "sha512-UTKx0jejJmmO1dwTHSJuRgrO8N6PMlkxRT6sew8N6NC3Bgv6pu0EbO+RtlWt/jCvzcdLOPdIoTzj4MMZvgcMYg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0"
+      }
+    },
+    "@parcel/compressor-raw": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.7.0.tgz",
+      "integrity": "sha512-SCXwnOOQT6EmpusBsYWNQ/RFri+2JnKuE0gMSf2dROl2xbererX45FYzeDplWALCKAdjMNDpFwU+FyMYoVZSCQ==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0"
+      }
+    },
+    "@parcel/config-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.7.0.tgz",
+      "integrity": "sha512-ZzsLr97AYrz8c9k6qn3DlqPzifi3vbP7q3ynUrAFxmt0L4+K0H9N508ZkORYmCgaFjLIQ8Y3eWpwCJ0AewPNIg==",
+      "dev": true,
+      "requires": {
+        "@parcel/bundler-default": "2.7.0",
+        "@parcel/compressor-raw": "2.7.0",
+        "@parcel/namer-default": "2.7.0",
+        "@parcel/optimizer-css": "2.7.0",
+        "@parcel/optimizer-htmlnano": "2.7.0",
+        "@parcel/optimizer-image": "2.7.0",
+        "@parcel/optimizer-svgo": "2.7.0",
+        "@parcel/optimizer-terser": "2.7.0",
+        "@parcel/packager-css": "2.7.0",
+        "@parcel/packager-html": "2.7.0",
+        "@parcel/packager-js": "2.7.0",
+        "@parcel/packager-raw": "2.7.0",
+        "@parcel/packager-svg": "2.7.0",
+        "@parcel/reporter-dev-server": "2.7.0",
+        "@parcel/resolver-default": "2.7.0",
+        "@parcel/runtime-browser-hmr": "2.7.0",
+        "@parcel/runtime-js": "2.7.0",
+        "@parcel/runtime-react-refresh": "2.7.0",
+        "@parcel/runtime-service-worker": "2.7.0",
+        "@parcel/transformer-babel": "2.7.0",
+        "@parcel/transformer-css": "2.7.0",
+        "@parcel/transformer-html": "2.7.0",
+        "@parcel/transformer-image": "2.7.0",
+        "@parcel/transformer-js": "2.7.0",
+        "@parcel/transformer-json": "2.7.0",
+        "@parcel/transformer-postcss": "2.7.0",
+        "@parcel/transformer-posthtml": "2.7.0",
+        "@parcel/transformer-raw": "2.7.0",
+        "@parcel/transformer-react-refresh-wrap": "2.7.0",
+        "@parcel/transformer-svg": "2.7.0"
+      }
+    },
+    "@parcel/core": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.7.0.tgz",
+      "integrity": "sha512-7yKZUdh314Q/kU/9+27ZYTfcnXS6VYHuG+iiUlIohnvUUybxLqVJhdMU9Q+z2QcPka1IdJWz4K4Xx0y6/4goyg==",
+      "dev": true,
+      "requires": {
+        "@mischnic/json-sourcemap": "^0.1.0",
+        "@parcel/cache": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/events": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/graph": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/package-manager": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "abortcontroller-polyfill": "^1.1.9",
+        "base-x": "^3.0.8",
+        "browserslist": "^4.6.6",
+        "clone": "^2.1.1",
+        "dotenv": "^7.0.0",
+        "dotenv-expand": "^5.1.0",
+        "json5": "^2.2.0",
+        "msgpackr": "^1.5.4",
+        "nullthrows": "^1.1.1",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/css": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmjs.org/@parcel/css/-/css-1.14.0.tgz",
+      "integrity": "sha512-r5tJWe6NF6lesfPw1N3g7N7WUKpHqi2ONnw9wl5ccSGGIxkmgcPaPQxfvmhdjXvQnktSuIOR0HjQXVXu+/en/w==",
+      "dev": true,
+      "requires": {
+        "lightningcss": "^1.14.0"
+      }
+    },
+    "@parcel/diagnostic": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.7.0.tgz",
+      "integrity": "sha512-pdq/cTwVoL0n8yuDCRXFRSQHVWdmmIXPt3R3iT4KtYDYvOrMT2dLPT79IMqQkhYPANW8GuL15n/WxRngfRdkug==",
+      "dev": true,
+      "requires": {
+        "@mischnic/json-sourcemap": "^0.1.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/events": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.7.0.tgz",
+      "integrity": "sha512-kQDwMKgZ1U4M/G17qeDYF6bW5kybluN6ajYPc7mZcrWg+trEI/oXi81GMFaMX0BSUhwhbiN5+/Vb2wiG/Sn6ig==",
+      "dev": true
+    },
+    "@parcel/fs": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.7.0.tgz",
+      "integrity": "sha512-PU5fo4Hh8y03LZgemgVREttc0wyHQUNmsJCybxTB7EjJie2CqJRumo+DFppArlvdchLwJdc9em03yQV/GNWrEg==",
+      "dev": true,
+      "requires": {
+        "@parcel/fs-search": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/watcher": "^2.0.0",
+        "@parcel/workers": "2.7.0"
+      }
+    },
+    "@parcel/fs-search": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.7.0.tgz",
+      "integrity": "sha512-K1Hv25bnRpwQVA15RvcRuB8ZhfclnCHA8N8L6w7Ul1ncSJDxCIkIAc5hAubYNNYW3kWjCC2SOaEgFKnbvMllEQ==",
+      "dev": true,
+      "requires": {
+        "detect-libc": "^1.0.3"
+      }
+    },
+    "@parcel/graph": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.7.0.tgz",
+      "integrity": "sha512-Q6E94GS6q45PtsZh+m+gvFRp/N1Qopxhu2sxjcWsGs5iBd6IWn2oYLWOH5iVzEjWuYpW2HkB08lH6J50O63uOA==",
+      "dev": true,
+      "requires": {
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/hash": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.7.0.tgz",
+      "integrity": "sha512-k6bSKnIlPJMPU3yjQzfgfvF9zuJZGOAlJgzpL4BbWvdbE8BTdjzLcFn0Ujrtud94EgIkiXd22sC2HpCUWoHGdA==",
+      "dev": true,
+      "requires": {
+        "detect-libc": "^1.0.3",
+        "xxhash-wasm": "^0.4.2"
+      }
+    },
+    "@parcel/logger": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.7.0.tgz",
+      "integrity": "sha512-qjMY/bYo38+o+OiIrTRldU9CwL1E7J72t+xkTP8QIcUxLWz5LYR0YbynZUVulmBSfqsykjjxCy4a+8siVr+lPw==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/events": "2.7.0"
+      }
+    },
+    "@parcel/markdown-ansi": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.7.0.tgz",
+      "integrity": "sha512-ipOX0D6FVZFEXeb/z8MnTMq2RQEIuaILY90olVIuHEFLHHfOPEn+RK3u13HA1ChF5/9E3cMD79tu6x9JL9Kqag==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0"
+      }
+    },
+    "@parcel/namer-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.7.0.tgz",
+      "integrity": "sha512-lIKMdsmi//7fepecNDYmJYzBlL91HifPsX03lJCdu1dC6q5fBs+gG0XjKKG7yPnSCw1qH/4m7drzt9+dRZYAHQ==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/node-resolver-core": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.7.0.tgz",
+      "integrity": "sha512-5UJQHalqMxdhJIs2hhqQzFfQpF7+NAowsRq064lYtiRvcD8wMr3OOQ9wd1iazGpFSl4JKdT7BwDU9/miDJmanQ==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/optimizer-css": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.7.0.tgz",
+      "integrity": "sha512-IfnOMACqhcAclKyOW9X9JpsknB6OShk9OVvb8EvbDTKHJhQHNNmzE88OkSI/pS3ZVZP9Zj+nWcVHguV+kvDeiQ==",
+      "dev": true,
+      "requires": {
+        "@parcel/css": "^1.12.2",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "browserslist": "^4.6.6",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/optimizer-htmlnano": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.7.0.tgz",
+      "integrity": "sha512-5QrGdWS5Hi4VXE3nQNrGqugmSXt68YIsWwKRAdarOxzyULSJS3gbCiQOXqIPRJobfZjnSIcdtkyxSiCUe1inIA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "htmlnano": "^2.0.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "svgo": "^2.4.0"
+      }
+    },
+    "@parcel/optimizer-image": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.7.0.tgz",
+      "integrity": "sha512-EnaXz5UjR67FUu0BEcqZTT9LsbB/iFAkkghCotbnbOuC5QQsloq6tw54TKU3y+R3qsjgUoMtGxPcGfVoXxZXYw==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "detect-libc": "^1.0.3"
+      }
+    },
+    "@parcel/optimizer-svgo": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.7.0.tgz",
+      "integrity": "sha512-IO1JV4NpfP3V7FrhsqCcV8pDQIHraFi1/ZvEJyssITxjH49Im/txKlwMiQuZZryAPn8Xb8g395Muawuk6AK6sg==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "svgo": "^2.4.0"
+      }
+    },
+    "@parcel/optimizer-terser": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.7.0.tgz",
+      "integrity": "sha512-07VZjIO8xsl2/WmS/qHI8lI/cpu47iS9eRpqwfZEEsdk1cfz50jhWkmFudHBxiHGMfcZ//1+DdaPg9RDBWZtZA==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "terser": "^5.2.0"
+      }
+    },
+    "@parcel/package-manager": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.7.0.tgz",
+      "integrity": "sha512-wmfSX1mRrTi8MeA4KrnPk/x7zGUsILCQmTo6lA4gygzAxDbM1pGuyFN8/Kt0y0SFO2lbljARtD/4an5qdotH+Q==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/packager-css": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.7.0.tgz",
+      "integrity": "sha512-44nzZwu+ssGuiFmYM6cf/Y4iChiUZ4DUzzpegnGlhXtKJKe4NHntxThJynuRZWKN2AAf48avApDpimg2jW0KDw==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/packager-html": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.7.0.tgz",
+      "integrity": "sha512-Zgqd7sdcY/UnR370GR0q2ilmEohUDXsO8A1F28QCJzIsR1iCB6KRUT74+pawfQ1IhXZLaaFLLYe0UWcfm0JeXg==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5"
+      }
+    },
+    "@parcel/packager-js": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.7.0.tgz",
+      "integrity": "sha512-wTRdM81PgRVDzWGXdWmqLwguWnTYWzhEDdjXpW2n8uMOu/CjHhMtogk65aaYk3GOnq6OBL/NsrmBiV/zKPj1vA==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "globals": "^13.2.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/packager-raw": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.7.0.tgz",
+      "integrity": "sha512-jg2Zp8dI5VpIQlaeahXDCfrPN9m/DKht1NkR9P2CylMAwqCcc1Xc1RRiF0wfwcPZpPMpq1265n+4qnB7rjGBlA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0"
+      }
+    },
+    "@parcel/packager-svg": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.7.0.tgz",
+      "integrity": "sha512-EmJg3HpD6/xxKBjir/CdCKJZwI24iVfBuxRS9LUp3xHAIebOzVh1z6IN+i2Di5+NyRwfOFaLliL4uMa1zwbyCA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "posthtml": "^0.16.4"
+      }
+    },
+    "@parcel/plugin": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.7.0.tgz",
+      "integrity": "sha512-qqgx+nnMn6/0lRc4lKbLGmhNtBiT93S2gFNB4Eb4Pfz/SxVYoW+fmml+KdfOSiZffWOAH5L6NwhyD7N8aSikzw==",
+      "dev": true,
+      "requires": {
+        "@parcel/types": "2.7.0"
+      }
+    },
+    "@parcel/reporter-cli": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.7.0.tgz",
+      "integrity": "sha512-80gEODg8cnAmnxGVuaSVDo8JJ54P9AA2bHwSs1cIkHWlJ3BjDQb83H31bBHncJ5Kn5kQ/j+7WjlqHpTCiOR9PA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "chalk": "^4.1.0",
+        "term-size": "^2.2.1"
+      }
+    },
+    "@parcel/reporter-dev-server": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.7.0.tgz",
+      "integrity": "sha512-ySuou5addK8fGue8aXzo536BaEjMujDrEc1xkp4TasInXHVcA98b+SYX5NAZTGob5CxKvZQ5ylhg77zW30B+iA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0"
+      }
+    },
+    "@parcel/resolver-default": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.7.0.tgz",
+      "integrity": "sha512-v8TvWsbLK7/q7n4gv6OrYNbW18xUx4zKbVMGZb1u4yMhzEH4HFr1D9OeoTq3jk+ximAigds8B6triQbL5exF7A==",
+      "dev": true,
+      "requires": {
+        "@parcel/node-resolver-core": "2.7.0",
+        "@parcel/plugin": "2.7.0"
+      }
+    },
+    "@parcel/runtime-browser-hmr": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.7.0.tgz",
+      "integrity": "sha512-PLbMLdclQeYsi2LkilZVGFV1n3y55G1jaBvby4ekedUZjMw3SWdMY2tDxgSDdFWfLCnYHJXdGUQSzGGi1kPzjA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0"
+      }
+    },
+    "@parcel/runtime-js": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.7.0.tgz",
+      "integrity": "sha512-9/YUZTBNrSN2H6rbz/o1EOM0O7I3ZR/x9IDzxjJBD6Mi+0uCgCD02aedare/SNr1qgnbZZWmhpOzC+YgREcfLA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/runtime-react-refresh": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.7.0.tgz",
+      "integrity": "sha512-vDKO0rWqRzEpmvoZ4kkYUiSsTxT5NnH904BFPFxKI0wJCl6yEmPuEifmATo73OuYhP6jIP3Qfl1R4TtiDFPJ1Q==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "react-error-overlay": "6.0.9",
+        "react-refresh": "^0.9.0"
+      }
+    },
+    "@parcel/runtime-service-worker": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.7.0.tgz",
+      "integrity": "sha512-uD2pAV0yV6+e7JaWH4KVPbG+zRCrxr/OACyS9tIh+Q/R1vRmh8zGM3yhdrcoiZ7tFOnM72vd6xY11eTrUsSVig==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/source-map": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz",
+      "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==",
+      "dev": true,
+      "requires": {
+        "detect-libc": "^1.0.3"
+      }
+    },
+    "@parcel/transformer-babel": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.7.0.tgz",
+      "integrity": "sha512-7iklDXXnKH1530+QbI+e4kIJ+Q1puA1ulRS10db3aUJMj5GnvXGDFwhSZ7+T1ps66QHO7cVO29VlbqiRDarH1Q==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "browserslist": "^4.6.6",
+        "json5": "^2.2.0",
+        "nullthrows": "^1.1.1",
+        "semver": "^5.7.0"
+      }
+    },
+    "@parcel/transformer-css": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.7.0.tgz",
+      "integrity": "sha512-J4EpWK9spQpXyNCmKK8Xnane0xW/1B/EAmfp7Fiv7g+5yUjY4ODf4KUugvE+Eb2gekPkhOKNHermO2KrX0/PFA==",
+      "dev": true,
+      "requires": {
+        "@parcel/css": "^1.12.2",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "browserslist": "^4.6.6",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/transformer-html": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.7.0.tgz",
+      "integrity": "sha512-wYJl5rn81W+Rlk9oQwDJcjoVsWVDKyeri84FzmlGXOsg0EYgnqOiG+3MDM8GeZjfuGe5fuoum4eqZeS0WdUHXw==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "posthtml-parser": "^0.10.1",
+        "posthtml-render": "^3.0.0",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/transformer-image": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.7.0.tgz",
+      "integrity": "sha512-mhi9/R5/ULhCkL2COVIKhNFoLDiZwQgprdaTJr5fnODggVxEX5o7ebFV6KNLMTEkwZUJWoB1hL0ziI0++DtoFA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@parcel/transformer-js": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.7.0.tgz",
+      "integrity": "sha512-mzerR+D4rDomUSIk5RSTa2w+DXBdXUeQrpDO74WCDdpDi1lIl8ppFpqtmU7O6y6p8QsgkmS9b0g/vhcry6CJTA==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/utils": "2.7.0",
+        "@parcel/workers": "2.7.0",
+        "@swc/helpers": "^0.4.2",
+        "browserslist": "^4.6.6",
+        "detect-libc": "^1.0.3",
+        "nullthrows": "^1.1.1",
+        "regenerator-runtime": "^0.13.7",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/transformer-json": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.7.0.tgz",
+      "integrity": "sha512-RQjuxBpYOch+kr4a0zi77KJtOLTPYRM7iq4NN80zKnA0r0dwDUCxZBtaj2l0O0o3R4MMJnm+ncP+cB7XR7dZYA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "json5": "^2.2.0"
+      }
+    },
+    "@parcel/transformer-postcss": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.7.0.tgz",
+      "integrity": "sha512-b6RskXBWf0MjpC9qjR2dQ1ZdRnlOiKYseG5CEovWCqM218RtdydFKz7jS+5Gxkb6qBtOG7zGPONXdPe+gTILcA==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "clone": "^2.1.1",
+        "nullthrows": "^1.1.1",
+        "postcss-value-parser": "^4.2.0",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/transformer-posthtml": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.7.0.tgz",
+      "integrity": "sha512-cP8YOiSynWJ1ycmBlhnnHeuQb2cwmklZ+BNyLUktj5p78kDy2de7VjX+dRNRHoW4H9OgEcSF4UEfDVVz5RYIhw==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "posthtml-parser": "^0.10.1",
+        "posthtml-render": "^3.0.0",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/transformer-raw": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.7.0.tgz",
+      "integrity": "sha512-sDnItWCFSDez0izK1i5cgv+kXzZTbcJh4rNpVIgmE1kBLvAz608sqgcCkavb2wVJIvLesxYM+5G4p1CwkDlZ1g==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0"
+      }
+    },
+    "@parcel/transformer-react-refresh-wrap": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.7.0.tgz",
+      "integrity": "sha512-1vRmIJzyBA1nIiXTAU6tZExq2FvJj/2F0ft6KDw8GYPv0KjmdiPo/PmaZ7JeSVOM6SdXQIQCbTmp1vkMP7DtkA==",
+      "dev": true,
+      "requires": {
+        "@parcel/plugin": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "react-refresh": "^0.9.0"
+      }
+    },
+    "@parcel/transformer-svg": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.7.0.tgz",
+      "integrity": "sha512-ioER37zceuuE+K6ZrnjCyMUWEnv+63hIAFResc1OXxRhyt+7kzMz9ZqK0Mt6QMLwl1dxhkLmrU41n9IxzKZuSQ==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/plugin": "2.7.0",
+        "nullthrows": "^1.1.1",
+        "posthtml": "^0.16.5",
+        "posthtml-parser": "^0.10.1",
+        "posthtml-render": "^3.0.0",
+        "semver": "^5.7.1"
+      }
+    },
+    "@parcel/types": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.7.0.tgz",
+      "integrity": "sha512-+dhXVUnseTCpJvBTGMp0V6X13z6O/A/+CUtwEpMGZ8XSmZ4Gk44GvaTiBOp0bJpWG4fvCKp+UmC8PYbrDiiziw==",
+      "dev": true,
+      "requires": {
+        "@parcel/cache": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/package-manager": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "@parcel/workers": "2.7.0",
+        "utility-types": "^3.10.0"
+      }
+    },
+    "@parcel/utils": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.7.0.tgz",
+      "integrity": "sha512-jNZ5bIGg1r1RDRKi562o4kuVwnz+XJ2Ie3b0Zwrqwvgfj6AbRFIKzDd+h85dWWmcDYzKUbHp11u6VJl1u8Vapg==",
+      "dev": true,
+      "requires": {
+        "@parcel/codeframe": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/hash": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/markdown-ansi": "2.7.0",
+        "@parcel/source-map": "^2.0.0",
+        "chalk": "^4.1.0"
+      }
+    },
+    "@parcel/watcher": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.5.tgz",
+      "integrity": "sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==",
+      "dev": true,
+      "requires": {
+        "node-addon-api": "^3.2.1",
+        "node-gyp-build": "^4.3.0"
+      }
+    },
+    "@parcel/workers": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.7.0.tgz",
+      "integrity": "sha512-99VfaOX+89+RaoTSyH9ZQtkMBFZBFMvJmVJ/GeJT6QCd2wtKBStTHlaSnQOkLD/iRjJCNwV2xpZmm8YkTwV+hg==",
+      "dev": true,
+      "requires": {
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/types": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "chrome-trace-event": "^1.0.2",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "@swc/helpers": {
+      "version": "0.4.12",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.12.tgz",
+      "integrity": "sha512-R6RmwS9Dld5lNvwKlPn62+piU+WDG1sMfsnfJioXCciyko/gZ0DQ4Mqglhq1iGU1nQ/RcGkAwfMH+elMSkJH3Q==",
+      "dev": true,
+      "requires": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "@trysound/sax": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
+      "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
+      "dev": true
+    },
+    "@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "dev": true
+    },
+    "abortcontroller-polyfill": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz",
+      "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==",
+      "dev": true
+    },
+    "acorn": {
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+      "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
+    "base-x": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
+      "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true
+    },
+    "browserslist": {
+      "version": "4.21.4",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
+      "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30001400",
+        "electron-to-chromium": "^1.4.251",
+        "node-releases": "^2.0.6",
+        "update-browserslist-db": "^1.0.9"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true
+    },
+    "caniuse-lite": {
+      "version": "1.0.30001423",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz",
+      "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==",
+      "dev": true
+    },
+    "chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      }
+    },
+    "chrome-trace-event": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+      "dev": true
+    },
+    "clone": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+      "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+      "dev": true
+    },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true
+    },
+    "cosmiconfig": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
+      "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
+      "dev": true,
+      "requires": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      }
+    },
+    "css-select": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+      "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+      "dev": true,
+      "requires": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.0.1",
+        "domhandler": "^4.3.1",
+        "domutils": "^2.8.0",
+        "nth-check": "^2.0.1"
+      }
+    },
+    "css-tree": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+      "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+      "dev": true,
+      "requires": {
+        "mdn-data": "2.0.14",
+        "source-map": "^0.6.1"
+      }
+    },
+    "css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true
+    },
+    "csso": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
+      "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
+      "dev": true,
+      "requires": {
+        "css-tree": "^1.1.2"
+      }
+    },
+    "detect-libc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+      "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+      "dev": true
+    },
+    "dom-serializer": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+      "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.0.1",
+        "domhandler": "^4.2.0",
+        "entities": "^2.0.0"
+      },
+      "dependencies": {
+        "entities": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+          "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+          "dev": true
+        }
+      }
+    },
+    "domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true
+    },
+    "domhandler": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+      "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.2.0"
+      }
+    },
+    "domutils": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+      "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "^1.0.1",
+        "domelementtype": "^2.2.0",
+        "domhandler": "^4.2.0"
+      }
+    },
+    "dotenv": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz",
+      "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==",
+      "dev": true
+    },
+    "dotenv-expand": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
+      "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
+      "dev": true
+    },
+    "electron-to-chromium": {
+      "version": "1.4.284",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
+      "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
+      "dev": true
+    },
+    "entities": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+      "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true
+    },
+    "get-port": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz",
+      "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==",
+      "dev": true
+    },
+    "globals": {
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "dev": true,
+      "requires": {
+        "type-fest": "^0.20.2"
+      }
+    },
+    "has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true
+    },
+    "htmlnano": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.2.tgz",
+      "integrity": "sha512-+ZrQFS4Ub+zd+/fWwfvoYCEGNEa0/zrpys6CyXxvZDwtL7Pl+pOtRkiujyvBQ7Lmfp7/iEPxtOFgxWA16Gkj3w==",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^7.0.1",
+        "posthtml": "^0.16.5",
+        "timsort": "^0.3.0"
+      }
+    },
+    "htmlparser2": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
+      "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.0.1",
+        "domhandler": "^4.2.2",
+        "domutils": "^2.8.0",
+        "entities": "^3.0.1"
+      }
+    },
+    "import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "requires": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "is-json": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
+      "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
+      "dev": true
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "json5": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
+      "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+      "dev": true
+    },
+    "lightningcss": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.16.0.tgz",
+      "integrity": "sha512-5+ZS9h+xeADcJTF2oRCT3yNZBlDYyOgQSdrWNBCqsIwm8ucKbF061OBVv/WHP4Zk8FToNhwFklk/hMuOngqsIg==",
+      "dev": true,
+      "requires": {
+        "detect-libc": "^1.0.3",
+        "lightningcss-darwin-arm64": "1.16.0",
+        "lightningcss-darwin-x64": "1.16.0",
+        "lightningcss-linux-arm-gnueabihf": "1.16.0",
+        "lightningcss-linux-arm64-gnu": "1.16.0",
+        "lightningcss-linux-arm64-musl": "1.16.0",
+        "lightningcss-linux-x64-gnu": "1.16.0",
+        "lightningcss-linux-x64-musl": "1.16.0",
+        "lightningcss-win32-x64-msvc": "1.16.0"
+      }
+    },
+    "lightningcss-darwin-arm64": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.16.0.tgz",
+      "integrity": "sha512-gIhz6eZFwsC4oVMjBGQ3QWDdLQY7vcXFyM/x91PilgHqu63B9uBa10EZA75YoTEkbKhoz0uDCqyHh/EoF1GrkQ==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-darwin-x64": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.16.0.tgz",
+      "integrity": "sha512-kLPi+OEpDj3UGY6DC8TfjbcULJDKMP+TVKSlrEkNGn8t1YRzi2g4oy7UVTSB5AnSbT0CusUItzdVjHQ49EdoNA==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-linux-arm-gnueabihf": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.16.0.tgz",
+      "integrity": "sha512-oSwEbvXUPr//H/ainBRJXTxHerlheee/KgkTTmAQWiVnt8HV+bRohTBWWPBy5ZArgiGLwj7ogv45istgljPN2Q==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-linux-arm64-gnu": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.16.0.tgz",
+      "integrity": "sha512-Drq9BSVIvmV9zsDJbCZWCulMvKMQWFIlYXPCKV/iwRj+ZAJ1BRngma0cNHB6uW7Wac8Jg04CJN5IA4ELE3J+cQ==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-linux-arm64-musl": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.16.0.tgz",
+      "integrity": "sha512-1QXWStnTEo4RFQf0mfGhRyNUeEHilCZ0NA97XgwKwrYr/M7sYKU/1HWY00dPxFJ6GITR2pfJGo9xi3ScSSBxbA==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-linux-x64-gnu": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.16.0.tgz",
+      "integrity": "sha512-gD2eQYD5OFs1p83R0TcMCEc5HRyJES4lR4THmclv7khm3dc9vc+2VT0kFBPxO1L2AwlZuvXaaMan7X1Ul7uSfA==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-linux-x64-musl": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.16.0.tgz",
+      "integrity": "sha512-HJsKeYxloEvg2WCQhtYPqzZUliLu9JBJNeI5y9cPQeDR/7ayGGLbVhJaotPtzJkElOFL/SaXsS+FRuH4w+yafg==",
+      "dev": true,
+      "optional": true
+    },
+    "lightningcss-win32-x64-msvc": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.16.0.tgz",
+      "integrity": "sha512-h4ayyAlOMLUHV9NdofcIu79aEjmly93adVxcg5wDJpkvMiwDTufEN30M8G4gGcjo1JE5jFjAcyQcRpXYkYcemA==",
+      "dev": true,
+      "optional": true
+    },
+    "lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "lmdb": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz",
+      "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==",
+      "dev": true,
+      "requires": {
+        "@lmdb/lmdb-darwin-arm64": "2.5.2",
+        "@lmdb/lmdb-darwin-x64": "2.5.2",
+        "@lmdb/lmdb-linux-arm": "2.5.2",
+        "@lmdb/lmdb-linux-arm64": "2.5.2",
+        "@lmdb/lmdb-linux-x64": "2.5.2",
+        "@lmdb/lmdb-win32-x64": "2.5.2",
+        "msgpackr": "^1.5.4",
+        "node-addon-api": "^4.3.0",
+        "node-gyp-build-optional-packages": "5.0.3",
+        "ordered-binary": "^1.2.4",
+        "weak-lru-cache": "^1.2.2"
+      },
+      "dependencies": {
+        "node-addon-api": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+          "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+          "dev": true
+        }
+      }
+    },
+    "mdn-data": {
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+      "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+      "dev": true
+    },
+    "monaco-editor": {
+      "version": "0.32.1",
+      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.32.1.tgz",
+      "integrity": "sha512-LUt2wsUvQmEi2tfTOK+tjAPvt7eQ+K5C4rZPr6SeuyzjAuAHrIvlUloTcOiGjZW3fn3a/jFQCONrEJbNOaCqbA==",
+      "dev": true
+    },
+    "msgpackr": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.7.2.tgz",
+      "integrity": "sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==",
+      "dev": true,
+      "requires": {
+        "msgpackr-extract": "^2.1.2"
+      }
+    },
+    "msgpackr-extract": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.1.2.tgz",
+      "integrity": "sha512-cmrmERQFb19NX2JABOGtrKdHMyI6RUyceaPBQ2iRz9GnDkjBWFjNJC0jyyoOfZl2U/LZE3tQCCQc4dlRyA8mcA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-linux-arm": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-linux-x64": "2.1.2",
+        "@msgpackr-extract/msgpackr-extract-win32-x64": "2.1.2",
+        "node-gyp-build-optional-packages": "5.0.3"
+      }
+    },
+    "node-addon-api": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+      "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
+      "dev": true
+    },
+    "node-gyp-build": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz",
+      "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==",
+      "dev": true
+    },
+    "node-gyp-build-optional-packages": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz",
+      "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==",
+      "dev": true
+    },
+    "node-releases": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
+      "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
+      "dev": true
+    },
+    "nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "requires": {
+        "boolbase": "^1.0.0"
+      }
+    },
+    "nullthrows": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
+      "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==",
+      "dev": true
+    },
+    "ordered-binary": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.4.0.tgz",
+      "integrity": "sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==",
+      "dev": true
+    },
+    "parcel": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.7.0.tgz",
+      "integrity": "sha512-pRYwnivwtNP0tip8xYSo4zCB0XhLt7/gJzP1p8OovCqkmFjG9VG+GW9TcAKqMIo0ovEa9tT+/s6gY1Qy+BONGQ==",
+      "dev": true,
+      "requires": {
+        "@parcel/config-default": "2.7.0",
+        "@parcel/core": "2.7.0",
+        "@parcel/diagnostic": "2.7.0",
+        "@parcel/events": "2.7.0",
+        "@parcel/fs": "2.7.0",
+        "@parcel/logger": "2.7.0",
+        "@parcel/package-manager": "2.7.0",
+        "@parcel/reporter-cli": "2.7.0",
+        "@parcel/reporter-dev-server": "2.7.0",
+        "@parcel/utils": "2.7.0",
+        "chalk": "^4.1.0",
+        "commander": "^7.0.0",
+        "get-port": "^4.2.0",
+        "v8-compile-cache": "^2.0.0"
+      }
+    },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "requires": {
+        "callsites": "^3.0.0"
+      }
+    },
+    "parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      }
+    },
+    "path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true
+    },
+    "picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "dev": true
+    },
+    "posthtml": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
+      "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
+      "dev": true,
+      "requires": {
+        "posthtml-parser": "^0.11.0",
+        "posthtml-render": "^3.0.0"
+      },
+      "dependencies": {
+        "posthtml-parser": {
+          "version": "0.11.0",
+          "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
+          "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
+          "dev": true,
+          "requires": {
+            "htmlparser2": "^7.1.1"
+          }
+        }
+      }
+    },
+    "posthtml-parser": {
+      "version": "0.10.2",
+      "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz",
+      "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==",
+      "dev": true,
+      "requires": {
+        "htmlparser2": "^7.1.1"
+      }
+    },
+    "posthtml-render": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
+      "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
+      "dev": true,
+      "requires": {
+        "is-json": "^2.0.1"
+      }
+    },
+    "react-error-overlay": {
+      "version": "6.0.9",
+      "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
+      "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==",
+      "dev": true
+    },
+    "react-refresh": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz",
+      "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==",
+      "dev": true
+    },
+    "regenerator-runtime": {
+      "version": "0.13.10",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz",
+      "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==",
+      "dev": true
+    },
+    "resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "stable": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
+      "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^4.0.0"
+      }
+    },
+    "svgo": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
+      "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
+      "dev": true,
+      "requires": {
+        "@trysound/sax": "0.2.0",
+        "commander": "^7.2.0",
+        "css-select": "^4.1.3",
+        "css-tree": "^1.1.3",
+        "csso": "^4.2.0",
+        "picocolors": "^1.0.0",
+        "stable": "^0.1.8"
+      }
+    },
+    "term-size": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
+      "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
+      "dev": true
+    },
+    "terser": {
+      "version": "5.15.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz",
+      "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/source-map": "^0.3.2",
+        "acorn": "^8.5.0",
+        "commander": "^2.20.0",
+        "source-map-support": "~0.5.20"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+          "dev": true
+        }
+      }
+    },
+    "timsort": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
+      "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
+      "dev": true
+    },
+    "tslib": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+      "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+      "dev": true
+    },
+    "type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true
+    },
+    "update-browserslist-db": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "dev": true,
+      "requires": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      }
+    },
+    "utility-types": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
+      "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==",
+      "dev": true
+    },
+    "v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "weak-lru-cache": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz",
+      "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==",
+      "dev": true
+    },
+    "xxhash-wasm": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz",
+      "integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==",
+      "dev": true
+    },
+    "yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "dev": true
+    }
+  }
+}

+ 48 - 0
Maple.App/MonacoEditor/package.json

@@ -0,0 +1,48 @@
+{
+  "name": "leaf-conf-editor",
+  "version": "0.1.0",
+  "description": "Leaf configuration file editor based on Monaco",
+  "source": "src/editor.html",
+  "browserlist": "chrome >= 86",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "start": "parcel",
+    "build": "parcel build --target src/editor.html src/editor.html && parcel build --target json.worker.js node_modules/monaco-editor/esm/vs/language/json/json.worker.js && parcel build --target editor.worker.js node_modules/monaco-editor/esm/vs/editor/editor.worker.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/YtFlow/Maple.git"
+  },
+  "author": "bdbai <[email protected]>",
+  "license": "Apache-2.0",
+  "bugs": {
+    "url": "https://github.com/YtFlow/Maple/issues"
+  },
+  "homepage": "https://github.com/YtFlow/Maple#readme",
+  "devDependencies": {
+    "monaco-editor": "^0.32.1",
+    "parcel": "^2.7.0"
+  },
+  "alias": {
+    "buffer": false,
+    "process": false
+  },
+  "targets": {
+    "src/editor.html": {
+      "publicUrl": "/MonacoEditor",
+      "distDir": "dist"
+    },
+    "json.worker.js": {
+      "context": "web-worker",
+      "distDir": "dist",
+      "publicUrl": "/MonacoEditor",
+      "sourceMap": false
+    },
+    "editor.worker.js": {
+      "context": "web-worker",
+      "distDir": "dist",
+      "publicUrl": "/MonacoEditor",
+      "sourceMap": false
+    }
+  }
+}

+ 148 - 0
Maple.App/MonacoEditor/src/completion.ts

@@ -0,0 +1,148 @@
+import * as monaco from 'monaco-editor'
+import * as facts from './facts'
+import { findIndexOfSections, ILeafConfStruct, parseSectionGeneral, parseStruct, trimComment } from './parse'
+
+function completeGeneralSection(
+    model: monaco.editor.ITextModel,
+    position: monaco.Position,
+    textUntilPosition: string,
+    struct: ILeafConfStruct,
+): monaco.languages.CompletionItem[] {
+    const lineId = position.lineNumber
+    const lineLen = model.getLineLength(lineId)
+    const eqPos = textUntilPosition.indexOf('=')
+    if (eqPos === -1) {
+        const filledKeys = new Set(parseSectionGeneral(model, struct).map(i => i.key))
+        const range = new monaco.Range(lineId, model.getLineFirstNonWhitespaceColumn(lineId), lineId, lineLen + 1)
+
+        return facts.GENERAL_SETTING_KEYS.filter(k => !filledKeys.has(k.name)).map(k => {
+            switch (k.name) {
+                case facts.SETTING_TUN:
+                    return {
+                        label: k.name,
+                        kind: monaco.languages.CompletionItemKind.Keyword,
+                        range,
+                        insertText: `${k.name} = auto`,
+                        documentation: k.desc,
+                    }
+                case facts.SETTING_LOGLEVEL:
+                    return {
+                        label: k.name,
+                        kind: monaco.languages.CompletionItemKind.Keyword,
+                        range,
+                        insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
+                        insertText: `${k.name} = \${1|${facts.LOG_LEVELS.join(',')}|}`,
+                        documentation: k.desc,
+                    }
+                case facts.SETTING_ROUTING_DOMAIN_RESOLVE:
+                    return {
+                        label: k.name,
+                        kind: monaco.languages.CompletionItemKind.Keyword,
+                        range,
+                        insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
+                        insertText: `${k.name} = \${1|true,false|}`,
+                        documentation: k.desc,
+                    }
+            }
+            return {
+                label: k.name,
+                kind: monaco.languages.CompletionItemKind.Keyword,
+                range,
+                insertText: k.name + ' = ',
+                documentation: k.desc,
+            }
+        })
+    }
+
+    const settingKey = textUntilPosition.substring(0, eqPos).trim()
+    const range = new monaco.Range(lineId, eqPos + 2, lineId, lineLen + 1)
+    switch (settingKey) {
+        case facts.SETTING_TUN:
+            return [{
+                label: 'auto',
+                kind: monaco.languages.CompletionItemKind.Keyword,
+                range,
+                insertText: ' auto',
+                documentation: 'TODO: doc',
+            }]
+        case facts.SETTING_LOGLEVEL:
+            return facts.LOG_LEVELS.map(l => ({
+                label: l,
+                kind: monaco.languages.CompletionItemKind.Keyword,
+                range,
+                insertText: ' ' + l,
+                documentation: 'TODO: doc',
+            }))
+        case facts.SETTING_ROUTING_DOMAIN_RESOLVE:
+            return [{
+                label: 'true',
+                kind: monaco.languages.CompletionItemKind.Keyword,
+                range,
+                insertText: ' true',
+                documentation: 'TODO: doc',
+            }, {
+                label: 'false',
+                kind: monaco.languages.CompletionItemKind.Keyword,
+                range,
+                insertText: ' false',
+                documentation: 'TODO: doc',
+            },]
+    }
+    return []
+}
+
+export const completionProvider: monaco.languages.CompletionItemProvider = {
+    triggerCharacters: [' ', '[', ',', '='],
+    provideCompletionItems(model, position) {
+        const textUntilPosition = model.getValueInRange({
+            startLineNumber: position.lineNumber,
+            startColumn: 1,
+            endLineNumber: position.lineNumber,
+            endColumn: position.column
+        })
+        if (textUntilPosition.includes('#')) {
+            // Inside a comment
+            return { suggestions: [] }
+        }
+        const sectionHeaderOpenMatch = textUntilPosition.match(/^(\s*)\[(\s*)/)
+        if (sectionHeaderOpenMatch) {
+            const sectionHeaderPos = sectionHeaderOpenMatch[1].length + 2
+            const textAfterPosition = trimComment(model.getValueInRange({
+                startLineNumber: position.lineNumber,
+                startColumn: position.column + 1,
+                endLineNumber: position.lineNumber,
+                endColumn: model.getLineLength(position.lineNumber) + 1
+            }))
+            let completionRangeEndCol = sectionHeaderPos
+            const sectionNameEndBracketPos = textAfterPosition.lastIndexOf(']')
+            if (sectionNameEndBracketPos !== -1) {
+                completionRangeEndCol = position.column + sectionNameEndBracketPos + 2
+            }
+            const suggestions = facts.KNOWN_SECTION_NAMES.map(sectionName => ({
+                label: `[${sectionName}]`,
+                kind: monaco.languages.CompletionItemKind.Module,
+                insertText: sectionName + ']',
+                range: {
+                    startLineNumber: position.lineNumber,
+                    startColumn: sectionHeaderPos,
+                    endLineNumber: position.lineNumber,
+                    endColumn: completionRangeEndCol,
+                }
+            }))
+            return { suggestions }
+        }
+
+        const struct = parseStruct(model)
+        const sectionIndex = findIndexOfSections(struct.sections, position.lineNumber)
+        if (sectionIndex === -1) {
+            return { suggestions: [] }
+        }
+        let suggestions: monaco.languages.CompletionItem[] = [];
+        switch (struct.sections[sectionIndex].sectionName) {
+            case facts.SECTION_GENERAL:
+                suggestions = completeGeneralSection(model, position, textUntilPosition, struct)
+                break;
+        }
+        return { suggestions }
+    },
+}

+ 3 - 0
Maple.App/MonacoEditor/src/decl.d.ts

@@ -0,0 +1,3 @@
+declare module "monaco-editor/esm/vs/editor/editor.main.js" {
+    export * from 'monaco-editor'
+}

+ 25 - 0
Maple.App/MonacoEditor/src/editor.html

@@ -0,0 +1,25 @@
+<!doctype html>
+<title>Leaf Config Editor for Maple</title>
+<meta name="viewport" content="width=device-width">
+<style>
+    * {
+        box-sizing: border-box;
+    }
+
+    body,
+    html {
+        margin: 0;
+        padding: 0;
+        height: 100%;
+    }
+
+    .loading {
+        position: absolute;
+    }
+
+</style>
+
+<p id="loading">Loading...</p>
+<div id="container" style="width:100%;height:100%;border:1px solid grey"></div>
+
+<script type="module" src="./init.ts"></script>

+ 61 - 0
Maple.App/MonacoEditor/src/facts.ts

@@ -0,0 +1,61 @@
+export const SECTION_ENV = 'Env'
+export const SECTION_GENERAL = 'General'
+export const SECTION_PROXY = 'Proxy'
+export const SECTION_PROXY_GROUP = 'Proxy Group'
+export const SECTION_RULE = 'Rule'
+export const SECTION_HOST = 'Host'
+export const KNOWN_SECTION_NAMES = [
+    SECTION_ENV,
+    SECTION_GENERAL,
+    SECTION_PROXY,
+    SECTION_PROXY_GROUP,
+    SECTION_RULE,
+    SECTION_HOST,
+]
+export const KNOWN_SECTION_NAMES_SET = new Set(KNOWN_SECTION_NAMES)
+
+export interface IGeneralSettingDef {
+    name: string,
+    desc: string,
+    kind: 'port' | 'interface' | 'other'
+}
+export const SETTING_TUN_FD = 'tun-fd'
+export const SETTING_TUN = 'tun'
+export const SETTING_LOGLEVEL = 'loglevel'
+export const SETTING_LOGOUTPUT = 'logoutput'
+export const SETTING_DNS_SERVER = 'dns-server'
+export const SETTING_DNS_INTERFACE = 'dns-interface'
+export const SETTING_ALWAYS_REAL_IP = 'always-real-ip'
+export const SETTING_ALWAYS_FAKE_IP = 'always-fake-ip'
+export const SETTING_ROUTING_DOMAIN_RESOLVE = 'routing-domain-resolve'
+export const SETTING_HTTP_INTERFACE = 'http-interface'
+export const SETTING_INTERFACE = 'interface'
+export const SETTING_HTTP_PORT = 'http-port'
+export const SETTING_PORT = 'port'
+export const SETTING_SOCKS_INTERFACE = 'socks-interface'
+export const SETTING_SOCKS_PORT = 'socks-port'
+export const SETTING_API_INTERFACE = 'api-interface'
+export const SETTING_API_PORT = 'api-port'
+
+export const GENERAL_SETTING_KEYS: IGeneralSettingDef[] = [
+    { name: SETTING_TUN_FD, desc: '', kind: 'other' },
+    { name: SETTING_TUN, desc: '', kind: 'other' },
+    { name: SETTING_LOGLEVEL, desc: '', kind: 'other' },
+    { name: SETTING_LOGOUTPUT, desc: '', kind: 'other' },
+    { name: SETTING_DNS_SERVER, desc: '', kind: 'other' },
+    { name: SETTING_DNS_INTERFACE, desc: '', kind: 'interface' },
+    { name: SETTING_ALWAYS_REAL_IP, desc: '', kind: 'other' },
+    { name: SETTING_ALWAYS_FAKE_IP, desc: '', kind: 'other' },
+    { name: SETTING_ROUTING_DOMAIN_RESOLVE, desc: '', kind: 'other' },
+    { name: SETTING_HTTP_INTERFACE, desc: '', kind: 'interface' },
+    { name: SETTING_INTERFACE, desc: '', kind: 'interface' },
+    { name: SETTING_HTTP_PORT, desc: '', kind: 'port' },
+    { name: SETTING_PORT, desc: '', kind: 'port' },
+    { name: SETTING_SOCKS_INTERFACE, desc: '', kind: 'interface' },
+    { name: SETTING_SOCKS_PORT, desc: '', kind: 'port' },
+    { name: SETTING_API_INTERFACE, desc: '', kind: 'interface' },
+    { name: SETTING_API_PORT, desc: '', kind: 'port' },
+]
+export const GENERAL_SETTINGS_KEYS_SET = new Set(GENERAL_SETTING_KEYS.map(k => k.name))
+
+export const LOG_LEVELS = ['trace', 'debug', 'info', 'warn', 'error']

+ 12 - 0
Maple.App/MonacoEditor/src/folding.ts

@@ -0,0 +1,12 @@
+import { languages } from 'monaco-editor'
+import { parseStruct } from './parse'
+
+export const foldingRangeProvider: languages.FoldingRangeProvider = {
+    provideFoldingRanges(model, _context, _token) {
+        const { sections } = parseStruct(model)
+        return sections.map(section => ({
+            start: section.startLine,
+            end: section.endLine,
+        }))
+    }
+}

+ 128 - 0
Maple.App/MonacoEditor/src/init.ts

@@ -0,0 +1,128 @@
+import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js'
+import { monarchTokenProvider } from './monarch'
+import { foldingRangeProvider } from './folding'
+import { completionProvider } from './completion'
+import { validateModel } from './validate'
+
+declare global {
+    interface Window {
+        pendingLoadFile: string | undefined
+        mapleHostApi: {
+            loadFile: (path: string) => void
+            triggerSave: () => void
+        }
+        MonacoEnvironment?: monaco.Environment | undefined,
+        chrome: {
+            webview: {
+                postMessage: typeof postMessage
+            }
+        }
+    }
+}
+
+function webviewInitPrelude() {
+    window.pendingLoadFile = undefined;
+    window.mapleHostApi = {
+        loadFile(url) {
+            console.log('pending loader triggered')
+            window.pendingLoadFile = url
+        },
+        triggerSave() { }
+    }
+    console.log('pending loader injected')
+}
+
+function initLang() {
+    self.MonacoEnvironment = {
+        getWorkerUrl: function (moduleId, label) {
+            if (label === 'json') {
+                return '/MonacoEditor/json.worker.js'
+            }
+            return '/MonacoEditor/editor.worker.js'
+        }
+    };
+
+    document.getElementById('loading')!.style.display = 'none'
+    monaco.languages.register({ id: 'leafConf' })
+    monaco.languages.setMonarchTokensProvider('leafConf', monarchTokenProvider)
+    monaco.languages.registerCompletionItemProvider('leafConf', completionProvider)
+    monaco.languages.registerFoldingRangeProvider('leafConf', foldingRangeProvider)
+
+    const editor = monaco.editor.create(document.getElementById('container')!)
+    const editorStates = new Map()
+
+    window.addEventListener('resize', _ => {
+        window.requestAnimationFrame(() => {
+            editor.layout()
+        })
+    })
+
+    let currentFile = ''
+    async function loadFile(url) {
+        triggerSave()
+        if (currentFile) {
+            editorStates.set(currentFile, editor.saveViewState())
+        }
+
+        // FIXME: destroy previous model?
+        const parsedUri = monaco.Uri.parse(url)
+        let maybeModel = monaco.editor.getModel(parsedUri)
+        do {
+            if (maybeModel) {
+                editor.setModel(maybeModel)
+                editor.restoreViewState(editorStates.get(url))
+            } else {
+                const res = await fetch(url)
+                const text = await res.text()
+                // Race condition
+                maybeModel = monaco.editor.getModel(parsedUri)
+                if (maybeModel) {
+                    continue
+                }
+
+                let model: monaco.editor.ITextModel
+                if (url.endsWith('.json')) {
+                    model = monaco.editor.createModel(text, 'json', parsedUri)
+                } else {
+                    model = monaco.editor.createModel(text, 'leafConf', parsedUri)
+                }
+                editor.setModel(model)
+                validateModel(model)
+                model.onDidChangeContent(() => validateModel(model))
+                console.log('loaded url: ' + url)
+            }
+        } while (false)
+        currentFile = url
+    }
+    function triggerSave() {
+        if (!currentFile) {
+            return
+        }
+        const text = editor.getValue()
+
+        window.chrome.webview.postMessage({
+            cmd: 'save',
+            path: currentFile,
+            text,
+        })
+    }
+    window.mapleHostApi.loadFile = loadFile
+    window.mapleHostApi.triggerSave = triggerSave
+
+    if (window.pendingLoadFile) {
+        loadFile(window.pendingLoadFile)
+    }
+    window.addEventListener('focusout', () => {
+        triggerSave()
+    })
+
+    editor.addAction({
+        id: 'save-action',
+        label: 'Save Current File',
+        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
+        run: () => void triggerSave(),
+    })
+}
+
+webviewInitPrelude()
+initLang()

+ 94 - 0
Maple.App/MonacoEditor/src/monarch.ts

@@ -0,0 +1,94 @@
+import { languages } from 'monaco-editor'
+
+export const monarchTokenProvider: languages.IMonarchLanguage = {
+    defaultToken: 'invalid',
+    tokenPostfix: '.ini',
+    includeLF: true,
+
+    typeKeywords: ['loglevel', 'tun', 'tun-fd', 'dns-server', 'dns-interface', 'always-real-ip', 'always-fake-ip', 'routing-domain-resolve', 'http-interface', 'interface', 'http-port', 'port', 'socks-interface', 'socks-port', 'api-interface', 'api-port', 'logoutput', 'auto', 'console',
+        'error', 'info', 'warn', 'trace', 'debug',
+        'true', 'false'],
+
+    // The main tokenizer for our languages
+    tokenizer: {
+        root: [
+            // whitespace
+            { include: '@whitespace' },
+
+            [/\n/, ''],
+
+            // section
+            [/\[[^\]#\n]+]/, { token: 'metatag', next: '@afterSection' }],
+
+            // before =
+            [/([\w-.:]+)(\s*)(=)/, [
+                {
+                    cases: {
+                        '@typeKeywords': 'keyword',
+                        '.*[\\\\\\./].*': 'string',
+                        '@default': 'key',
+                    }
+                },
+                '',
+                { token: 'delimiter', next: '@paramGroup' }
+            ]],
+
+            // rules
+            [/(?=.)/, { token: '', next: '@paramGroup' }],
+        ],
+
+        afterSection: [
+            { include: '@whitespace' },
+            [/\n/, 'metatag', '@pop'],
+        ],
+
+        paramGroup: [
+            { include: '@whitespace' },
+            [/\n/, '', '@pop'],
+            [/[\d:\/\.]+(?=[ \t,\n])/, 'number'],
+            [/([^\n#,]+)([ \t]*)(?=,|\n|#)/, [{
+                cases: {
+                    '@typeKeywords': 'keyword',
+                    '.*[\\\\\\./].*': 'string',
+                    '@default': 'type',
+                }
+            }, '']],
+            [/,/, { token: 'delimiter', switchTo: 'paramGroupRem' }]
+        ],
+
+        paramGroupRem: [
+            // site:category-ads-all
+            ['(site|mmdb)(:)([^#:,]+)(:?)([^#,\n]*)', ['keyword', 'delimiter', 'string', 'delimiter', 'string']],
+            // health-check=true
+            [/([^#=,]+)([ \t]*)(=)/, ['keyword', '', {
+                token: 'delimiter',
+                switchTo: '@paramValue',
+            }]],
+            { include: '@paramValue' },
+        ],
+
+        paramValue: [
+            { include: '@whitespace' },
+            [/(?=\n)/, '', '@pop'],
+            [/,/, { token: 'delimiter', switchTo: 'paramGroupRem' }],
+            [/[\d:\/\.]+(?=[ \t,\n])/, 'number'],
+            [/([^\n#,]+)([ \t]*)(?=,|\n|#)/, [{
+                cases: {
+                    '@typeKeywords': 'keyword',
+                    '.*[\\\\\\./-].*': 'string',
+                    '@default': 'key',
+                }
+            }, '']],
+        ],
+
+        comment: [
+            [/(?=\n)/, '', '@pop'],
+            [/./, 'comment'],
+        ],
+
+        whitespace: [
+            [/[ \t\r]+/, ''],
+            [/#/, 'comment', '@comment'],
+        ],
+    }
+}

+ 123 - 0
Maple.App/MonacoEditor/src/parse.ts

@@ -0,0 +1,123 @@
+import * as monaco from 'monaco-editor'
+import { SECTION_GENERAL } from './facts'
+
+export interface ILeafConfSection {
+    sectionName: string,
+    sectionNameStartCol: number,
+    startLine: number,
+    endLine: number,
+}
+
+export interface ILeafConfStruct {
+    sections: ILeafConfSection[]
+}
+
+export interface ILeafConfGeneralItem {
+    lineId: number,
+    key: string,
+    keyStartCol: number,
+    value: string,
+    valueStartCol: number,
+}
+
+export function trimWithPos(s: string, startCol: number) {
+    const matches = s.match(/^(\s*)([^\s].*)$/)
+    if (!matches) {
+        return { trimmed: '', startCol }
+    }
+    const [_, whitespace, text] = matches
+    return { trimmed: text.trimEnd(), startCol: startCol + whitespace.length }
+}
+
+export function trimComment(s: string): string {
+    const commentPos = s.indexOf('#')
+    if (commentPos === -1) {
+        return s
+    }
+    return s.slice(0, commentPos)
+}
+
+export function parseStruct(model: monaco.editor.ITextModel): ILeafConfStruct {
+    const ret: ILeafConfStruct = { sections: [] }
+    const sectionHeaderMatches = model.findMatches(`^(\\s*)\\[([^\\]#]+)\\]`, true, true, true, null, true)
+    const [firstSectionHeaderMatch, ...remainingSectionHeaderMatches] = sectionHeaderMatches
+    if (!firstSectionHeaderMatch) {
+        return ret
+    }
+    let { trimmed: sectionName, startCol: sectionNameStartCol } = trimWithPos(
+        firstSectionHeaderMatch.matches?.[2] || '',
+        (firstSectionHeaderMatch.matches?.[1].length ?? 0) + 2,
+    )
+    let lastSection = {
+        sectionName,
+        sectionNameStartCol,
+        startLine: firstSectionHeaderMatch.range.startLineNumber,
+        endLine: firstSectionHeaderMatch.range.startLineNumber
+    }
+    for (const sectionHeaderMatch of remainingSectionHeaderMatches) {
+        const currentLineId = sectionHeaderMatch.range.startLineNumber
+        let lastSectionLastLineId = currentLineId - 1
+        while (
+            lastSectionLastLineId > 1
+            && model.getLineFirstNonWhitespaceColumn(lastSectionLastLineId) === model.getLineLastNonWhitespaceColumn(lastSectionLastLineId)
+        ) {
+            lastSectionLastLineId--
+        }
+        lastSection.endLine = lastSectionLastLineId
+        ret.sections.push(lastSection)
+        const trimmedSectionName = trimWithPos(
+            firstSectionHeaderMatch.matches?.[2] || '',
+            (firstSectionHeaderMatch.matches?.[1].length ?? 0) + 2,
+        )
+        sectionName = trimmedSectionName.trimmed
+        sectionNameStartCol = trimmedSectionName.startCol
+        lastSection = {
+            sectionName,
+            sectionNameStartCol,
+            startLine: currentLineId,
+            endLine: currentLineId,
+        }
+    }
+    lastSection.endLine = model.getLineCount()
+    ret.sections.push(lastSection)
+    return ret
+}
+
+export function findIndexOfSections(sections: ILeafConfSection[], lineId: number): number {
+    // TODO: binary search
+    const pos = [...sections].reverse().findIndex(s => s.startLine < lineId)
+    if (pos === -1) {
+        return -1
+    }
+    return sections.length - pos - 1
+}
+
+export function parseGeneralLine(s: string, lineId: number, startCol: number): ILeafConfGeneralItem | undefined {
+    s = trimComment(s)
+    const eqPos = s.indexOf('=')
+    if (eqPos === -1) {
+        return undefined
+    }
+
+    const { trimmed: key, startCol: keyStartCol } = trimWithPos(s.substring(0, eqPos), startCol)
+    const { trimmed: value, startCol: valueStartCol } = trimWithPos(s.substring(eqPos + 1), startCol + eqPos + 1)
+    return { lineId, key, keyStartCol, value, valueStartCol }
+}
+
+export function parseSectionGeneral(
+    model: monaco.editor.ITextModel,
+    struct: ILeafConfStruct,
+): ILeafConfGeneralItem[] {
+    let ret: ILeafConfGeneralItem[] = []
+    for (const lineId of struct.sections
+        .filter(s => s.sectionName === SECTION_GENERAL)
+        .flatMap(s => Array.from({ length: s.endLine - s.startLine }, (_, i) => i + s.startLine + 1))) {
+
+        const line = model.getLineContent(lineId)
+        const item = parseGeneralLine(line, lineId, 1)
+        if (item !== undefined) {
+            ret.push(item)
+        }
+    }
+    return ret
+}

+ 56 - 0
Maple.App/MonacoEditor/src/validate.ts

@@ -0,0 +1,56 @@
+import * as monaco from 'monaco-editor'
+import { KNOWN_SECTION_NAMES, KNOWN_SECTION_NAMES_SET } from './facts'
+import { parseStruct, trimComment, trimWithPos } from './parse'
+
+export function validateModel(model: monaco.editor.ITextModel) {
+    const lineCount = model.getLineCount()
+    const { sections } = parseStruct(model)
+    const errors: monaco.editor.IMarkerData[] = []
+    const firstSectionLineId = sections?.[0].startLine ?? lineCount + 1
+    let currLineId = 1
+    while (currLineId < firstSectionLineId) {
+        const { trimmed, startCol } = trimWithPos(trimComment(model.getLineContent(currLineId)), 1)
+        if (trimmed.length > 0) {
+            errors.push({
+                severity: monaco.MarkerSeverity.Error,
+                message: `Content does not belong to any section`,
+                startLineNumber: currLineId,
+                startColumn: startCol,
+                endLineNumber: currLineId,
+                endColumn: startCol + trimmed.length,
+            })
+        }
+        currLineId++
+    }
+    for (const section of sections) {
+        const sectionHeader = trimComment(model.getLineContent(section.startLine)).trimEnd()
+        const sectionNameEndMarkPos = sectionHeader.lastIndexOf(']') + 1
+        if (sectionNameEndMarkPos !== sectionHeader.length) {
+            const { trimmed: extraContent, startCol: extraContentStartCol } =
+                trimWithPos(sectionHeader.substring(sectionNameEndMarkPos), sectionNameEndMarkPos + 1)
+            errors.push({
+                severity: monaco.MarkerSeverity.Error,
+                message: `Unexpected content after section header`,
+                startLineNumber: section.startLine,
+                startColumn: extraContentStartCol,
+                endLineNumber: section.startLine,
+                endColumn: extraContentStartCol + extraContent.length,
+            })
+        }
+
+        if (!KNOWN_SECTION_NAMES_SET.has(section.sectionName)) {
+            errors.push({
+                severity: monaco.MarkerSeverity.Error,
+                message: `Unknown section name: ${section.sectionName}
+Section names can only be one of: ${KNOWN_SECTION_NAMES.join(', ')}`,
+                startLineNumber: section.startLine,
+                startColumn: section.sectionNameStartCol,
+                endLineNumber: section.startLine,
+                endColumn: section.sectionNameStartCol + section.sectionName.length,
+            })
+        }
+        currLineId = section.startLine + 1
+    }
+    // const [doc, errors] = parseModel(model)
+    monaco.editor.setModelMarkers(model, 'Maple', errors)
+}

+ 4 - 1
Maple.App/packages.config

@@ -1,4 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="Microsoft.Windows.CppWinRT" version="2.0.210312.4" targetFramework="native" />
+  <package id="Microsoft.UI.Xaml" version="2.8.1" targetFramework="native" />
+  <package id="Microsoft.Web.WebView2" version="1.0.1370.28" targetFramework="native" />
+  <package id="Microsoft.Windows.CppWinRT" version="2.0.220929.3" targetFramework="native" />
+  <package id="nlohmann.json" version="3.11.2" targetFramework="native" />
 </packages>

+ 3 - 0
Maple.App/pch.h

@@ -22,3 +22,6 @@
 #include <winrt/Windows.UI.Xaml.Markup.h>
 #include <winrt/Windows.UI.Xaml.Navigation.h>
 #include <winrt/Windows.UI.Xaml.Shapes.h>
+
+#include <winrt/Microsoft.UI.Xaml.Controls.h>
+#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>

+ 9 - 2
Maple.Task/Maple.Task.vcxproj

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.props')" />
+  <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" />
   <PropertyGroup Label="Globals">
     <CppWinRTOptimized>true</CppWinRTOptimized>
     <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
@@ -170,6 +170,13 @@
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
-    <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.210312.4\build\native\Microsoft.Windows.CppWinRT.targets')" />
+    <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
   </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
+  </Target>
 </Project>

+ 1 - 1
Maple.Task/packages.config

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="Microsoft.Windows.CppWinRT" version="2.0.210312.4" targetFramework="native" />
+  <package id="Microsoft.Windows.CppWinRT" version="2.0.220929.3" targetFramework="native" />
 </packages>